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;
}
posted @ 2025-12-04 17:10  CJzdc  阅读(2)  评论(0)    收藏  举报