QOJ.ac
QOJ
ID | 题目 | 提交者 | 结果 | 用时 | 内存 | 语言 | 文件大小 | 提交时间 | 测评时间 |
---|---|---|---|---|---|---|---|---|---|
#510524 | #1436. Split in Sets | qL | WA | 0ms | 3984kb | C++14 | 2.9kb | 2024-08-09 08:30:11 | 2024-08-09 08:30:11 |
Judging History
answer
/**
* 位运算最优化,考虑逐位贪心。
* 因为是盒子内 AND,现在考察第 k 位上 0/1 的个数,记为 c0/c1。
* 套路地想令当前位尽量为 1,那么尝试讨论一下。
* 若 c1<m,则可以将每个 1 单独一盒,剩下数与盒的之后考虑。
* 此时往定下的任意盒中插入 0 的都会丢失当前位的贡献,因此是最优的。
* 而当 c1>=m 的时候,若存在 0,则必定是 m-1 个放 1,而所有当前位为 0 的数放进同一个盒子中。
* 因此可以把 0 的数全都 AND 起来,当作一个整体,然后将 c1+1 个数留到下一位分配。
* 此时答案有了,考虑方案数。
* 如果盒子互不区分,那么答案的方案数只有第 0 位影响。
* 不妨最后乘上 m!,考虑第 0 位,再次分讨。
* 若 c1<m,则需将 c0 个数放入剩下的 m-c1 个盒子;否则只需将 c1+1 个数分配给 m 个盒子。
* 那么这就是第二类斯特林数,求解方法可以考虑令 F(i) 表示 n 个不同的球放入 m 个不同的非空盒子,那么 m!strling(n,m)=F(m)。
* 然后 G(i) 表示 n 个不同的球放入 m 个不同的盒子,G(i)=i^n,而 F(i) 可以由 G(i) 二项式反演得出。
*/
#include <algorithm>
#include <cassert>
#include <cstdio>
#include <vector>
using i32 = int;
using i64 = long long;
constexpr i32 N = 1E5;
constexpr i32 mod = 1e9 + 7;
i32 n, m, arr[N + 1];
i64 fac[N + 1], ifac[N + 1];
i64 qpow(i64 x, i64 p) noexcept {
i64 r = 1;
for (; p; p >>= 1, (x *= x) %= mod)
if (p & 1) (r *= x) %= mod;
return r;
}
i64 binom(i32 n, i32 m) noexcept { return fac[n] * ifac[m] % mod * ifac[n - m] % mod; }
i32 strling(i32 n, i32 m) noexcept {
i64 r = 0;
for (i32 i = 0; i <= m; ++i) (r += ((m - i) & 1 ? -1 : 1) * binom(m, i) * qpow(i, n)) %= mod;
return (r + mod) * ifac[m] % mod;
}
signed main() noexcept {
scanf("%d%d", &n, &m), fac[0] = ifac[0] = 1;
for (i32 i = 1; i <= n; ++i) scanf("%d", &arr[i]), fac[i] = fac[i - 1] * i % mod;
ifac[n] = qpow(fac[n], mod - 2);
for (i32 i = n; i > 1; --i) ifac[i - 1] = ifac[i] * i % mod;
std::vector<i32> all(arr + 1, arr + n + 1);
i64 ans = 0, cnt = fac[m];
for (i32 k = 30; k; --k) {
assert(m <= i32(all.size()));
std::vector<i32> t[2];
for (i32 it : all) t[it >> k & 1].emplace_back(it);
if (i32(t[1].size()) < m) {
for (i32 it : t[1]) ans += it & ((1 << k) - 1);
ans += t[1].size() << k, all = t[0], m -= t[1].size();
} else {
ans += i64(m - !t[0].empty()) << k, all = t[1];
i32 sum = 0b1111111111111111111111111111111;
for (i32 it : t[0]) sum &= it;
if (!t[0].empty()) all.emplace_back(sum);
}
}
i32 c1 = std::count_if(all.begin(), all.end(), [](i32 x) noexcept { return x & 1; }), c0 = all.size() - c1;
(cnt *= c1 < m ? strling(c0, m - c1) : strling(c1 + bool(c0), m)) %= mod;
printf("%lld %lld\n", ans, cnt);
return 0;
}
詳細信息
Test #1:
score: 100
Accepted
time: 0ms
memory: 3768kb
input:
3 2 4 7 5
output:
11 2
result:
ok 2 tokens
Test #2:
score: 0
Accepted
time: 0ms
memory: 3952kb
input:
4 1 44 47 74 77
output:
8 1
result:
ok 2 tokens
Test #3:
score: 0
Accepted
time: 0ms
memory: 3952kb
input:
4 4 44 47 74 77
output:
242 24
result:
ok 2 tokens
Test #4:
score: -100
Wrong Answer
time: 0ms
memory: 3984kb
input:
1000 975 633065 7087 25267 3940676 618039 1695 2043 728466935 3498 13604984 4 99 119488 151315 12 32 52705062 26815 1902279 33952 480604 390647001 60 1 12566875 7591859 6 119892 7829822 2129 4 11644639 17 33200 5330 338 2 9 6862 3781 148087 57 198 13224999 10493180 1 5755424 216 1757297 210 1002623 ...
output:
35467198591 671056390
result:
wrong answer 1st words differ - expected: '35467198613', found: '35467198591'