Description
有 n 个区间 [l1,r1],[l2,r2],…[ln,rn]。对于每个 x 从 0 到 2m−1,求满足以下条件的序列 a1,a2,…an 的数量(模 998244353):
- 对于所有 i 从 1 到 n,有 li≤ai≤ri;
- a1⊕a2⊕…⊕an=x,其中 ⊕ 表示按位异或运算符。
1≤n≤2×105,1≤m≤18。
Solution
显然是 fwt。考虑求出 [li,ri] 对应的 fwt 数组。设 pc(x)=popcount(x)。
先把 [li,ri] 变成 [0,ri]−[0,li−1],现在问题变为求出 ∑i=0n(−1)pc(x&i)。
现在把 x 的 lowbit 拿出来,假设为 2b,那么对于所有 i 在 b 位之前没有顶到 n 的上界的所有数,由于 b 位的存在,一定会互相抵消。
然后再分讨一下可以发现答案为 (−1)pc(n&x)[nmod2b+1−(n&2b)],设 vb,n=nmod2b+1−(n&2b)。
那么 fwtx=i=1∏n[(−1)pc(ri&x)vb,ri−(−1)pc((li−1)&x)vb,li−1]。
容易想到枚举 b,每次求上面的那个东西,再化简一下:
fwtx===i=1∏n[(−1)pc(ri&x)vb,ri−(−1)pc((li−1)&x)vb,li−1]i=1∏n[(−1)pc((li−1)&x)vb,li−1⋅(−1+vb,li−1vb,ri⋅(−1)pc(ri&x)+pc((li−1)&x))]i=1∏n[(−1)pc((li−1)&x)vb,li−1⋅(−1+vb,li−1vb,ri⋅(−1)pc((ri⊕(li−1))&x))]
那个小括号外面的部分可以直接用类似 fwt 的东西做。小括号里面的东西是形如 ∏(ai+bixci) 的东西,也是个经典技巧,设 fwtx,0/1 表示目前 ∏(ai+bixci) 的乘积和 ∏(ai−bixci),具体转移看代码。
时间复杂度:O(nm+2m⋅m)。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
| #include <bits/stdc++.h>
const int kMaxN = 3e5 + 5, kMod = 998244353;
int n, m; int l[kMaxN], r[kMaxN], f[kMaxN];
int qpow(int bs, int64_t idx = kMod - 2) { int ret = 1; for (; idx; idx >>= 1, bs = (int64_t)bs * bs % kMod) if (idx & 1) ret = (int64_t)ret * bs % kMod; return ret; }
inline int add(int x, int y) { return (x + y >= kMod ? x + y - kMod : x + y); } inline int sub(int x, int y) { return (x >= y ? x - y : x - y + kMod); } inline void inc(int &x, int y) { (x += y) >= kMod ? x -= kMod : x; } inline void dec(int &x, int y) { (x -= y) < 0 ? x += kMod : x; } inline int getop(int x) { return (~x & 1) ? 1 : (kMod - 1); }
void ifwt(int *f, int n) { static const int kInv2 = (kMod + 1) / 2; for (int i = 0; i < n; ++i) { int m = (1 << i), len = 2 * m; for (int b = 0; b < (1 << n); b += len) { for (int j = b; j < b + m; ++j) { int val = f[j]; f[j] = 1ll * kInv2 * add(val, f[j | m]) % kMod; f[j | m] = 1ll * kInv2 * sub(val, f[j | m]) % kMod; } } } }
void dickdreamer() { std::cin >> n >> m; for (int i = 1; i <= n; ++i) std::cin >> l[i] >> r[i]; for (int bb = 0; bb < m; ++bb) { static int fwt[kMaxN][2]; int mm = m - bb; for (int i = 0; i < (1 << mm); ++i) fwt[i][0] = fwt[i][1] = 1; int coef = 1; for (int i = 1; i <= n; ++i) { int vl = 0, vr = sub((r[i] & ((1 << bb) - 1)) + 1, (r[i] & (1 << bb))); if (l[i]) vl = sub(((l[i] - 1) & ((1 << bb) - 1)) + 1, (l[i] - 1) & (1 << bb)); int a, b, c; if (vl) { coef = 1ll * coef * vl % kMod; a = kMod - 1, b = 1ll * vr * qpow(vl) % kMod, c = ((r[i] ^ (l[i] - 1)) >> bb); fwt[(l[i] - 1) >> bb][1] = sub(0, fwt[(l[i] - 1) >> bb][1]); } else { a = 0, b = vr, c = (r[i] >> bb); } fwt[c][0] = 1ll * fwt[c][0] * add(a, b) % kMod; fwt[c][1] = 1ll * fwt[c][1] * sub(a, b) % kMod; } for (int i = 0; i < mm; ++i) { int m = (1 << i), len = 2 * m; for (int k = 0; k < (1 << mm); k += len) { for (int j = k; j < k + m; ++j) { int tmp[2] = {fwt[j][0], fwt[j][1]}, tmp1[2] = {fwt[j | m][0], fwt[j | m][1]}; fwt[j][0] = 1ll * tmp[0] * tmp1[0] % kMod; fwt[j][1] = 1ll * tmp[1] * tmp1[1] % kMod; fwt[j | m][0] = 1ll * tmp[0] * tmp1[1] % kMod; fwt[j | m][1] = 1ll * tmp[1] * tmp1[0] % kMod; } } } for (int i = 1; i < (1 << mm); i += 2) { f[i << bb] = 1ll * coef * fwt[i][0] % kMod; } } f[0] = 1; for (int i = 1; i <= n; ++i) f[0] = 1ll * f[0] * (r[i] - l[i] + 1) % kMod; ifwt(f, m); int res = 0; for (int i = 0; i < (1 << m); ++i) res ^= (1ll * f[i] * qpow(2, i) % kMod); std::cout << res << '\n'; }
int32_t main() { #ifdef ORZXKR freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0); int T = 1; std::cin >> T; while (T--) dickdreamer(); return 0; }
|