QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#510524#1436. Split in SetsqLWA 0ms3984kbC++142.9kb2024-08-09 08:30:112024-08-09 08:30:11

Judging History

你现在查看的是最新测评结果

  • [2024-08-09 08:30:11]
  • 评测
  • 测评结果:WA
  • 用时:0ms
  • 内存:3984kb
  • [2024-08-09 08:30:11]
  • 提交

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;
}

Details

Tip: Click on the bar to expand more detailed information

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'