CF1770F Koxia and Sequence
\(a\) 可以重排,因此对于所有值 \(v\),其出现次数 \(c\) 将 \(n\) 划分为若干个子集。
考虑一个二分图,左部点是 \(n\) 的位,右部点是 \(y\) 的位,那么相当于对于每个左部点,在右部点选择一个集合连边。同时要求右部点的度数都要 \(\ge 1\)。此时每有一条边 \((i,j)\),那么就把 \(2^{i+j}\) 统计进和。
这里的左右不对称,对右部点容斥掉 \(\ge 1\) 限制,此时左右就是等价的了。
考虑怎么求答案。一个想法是拆位,算存在边 \((0,k)\) 的方案数。于是现在就有若干条 \(2^w\) 边可以任选,然后需要凑出 \(x-2^k\)。
继续观察 \(\bmod 2\) 的性质,对于某一个 \(2^w\),设其有 \(c\) 条边,使用了 \(t\) 条,那么方案数就是 \(\binom{c}{t}\),而我们也希望这个值 \(=1\),即 \(t\) 为 \(c\) 子集。
这个过程和二进制拆分实际上是一致的,重复模拟得到的就是总和的二进制,现在体积两两不同,只要判一下子集即可。总复杂度 \(O(y\log y)\)。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
// freopen("1.in", "r", stdin);
// freopen("1.out", "w", stdout);
ios::sync_with_stdio(0), cin.tie(0);
ll n, x, y;
cin >> n >> x >> y;
if(!(n & 1)) {
cout << "0\n";
return 0;
}
auto In = [&](ll x, ll y) {
return (x & y) == x;
};
ll res = 0;
for(ll s = y; s; s = (s - 1) & y) {
for(int w = 0; w < 60; w++) {
if(!((s >> w) & 1)) continue;
if(In(x - (1ll << w), n * s - (1ll << w))) {
res ^= (1ll << w);
}
}
}
cout << res << "\n";
return 0;
}
浙公网安备 33010602011771号