牛客36G NIM游戏(FWT)
牛客36G NIM游戏(FWT)
题目大意
求
\[\prod_{\oplus a_i = 0}b_i
\]
解题思路
牛逼提
我们把 \(a_i\) 相同的合并到一块,设生成函数为 \(F_i = 1 + b_ix^{i}\)
答案就是把 F 都乘起来,考虑 FWT
\[Ans = IFWT(\prod FWT(1+b_jx^{j}))_0\\
=\sum_{i=0}^{lim}\prod FWT(1+b_jx^{j})\\
=\sum_{i=0}^{lim}\prod (1+(-1)^{|i\&j|}b_j)\\
\]
这个也可以用分治乘法那样的形式做,设 \(h[x][c] = \prod(1+(-1)^{|x\&i|+c}b_i)\)
我们从低位到高位一个一个填,有
\[h[k][0] = h[k][0] \times h[k+t][0]\\
h[k][1] = h[k][1] \times h[k+t][1]\\
h[k+t][0] = h[k][0] \times h[k+t][1]\\
h[k+t][1] = h[k][1] \times h[k+t][0]\\
\]
代码
#include <queue>
#include <vector>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MP make_pair
#define ll long long
#define fi first
#define se second
using namespace std;
template <typename T>
void read(T &x) {
x = 0; bool f = 0;
char c = getchar();
for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
for (;isdigit(c);c=getchar()) x=x*10+(c^48);
if (f) x=-x;
}
template<typename F>
inline void write(F x, char ed = '\n')
{
static short st[30];short tp=0;
if(x<0) putchar('-'),x=-x;
do st[++tp]=x%10,x/=10; while(x);
while(tp) putchar('0'|st[tp--]);
putchar(ed);
}
template <typename T>
inline void Mx(T &x, T y) { x < y && (x = y); }
template <typename T>
inline void Mn(T &x, T y) { x > y && (x = y); }
const int N = 200500;
const int P = 998244353;
ll dp[N][2], ans, n;
ll fpw(ll x, ll mi) {
ll res = 1;
for (; mi; mi >>= 1, x = x * x % P)
if (mi & 1) res = res * x % P;
return res;
}
int main() {
read(n); int m = 1 << 17;
// for (int i = 1;i < m; i++) siz[i] = siz[i >> 1] + (i & 1);
for (int i = 0;i < m; i++) dp[i][0] = dp[i][1] = 1;
for (int i = 1, x, y;i <= n; i++) {
read(x), read(y);
dp[x][0] = dp[x][0] * (1 + y) % P;
dp[x][1] = dp[x][1] * (P + 1 - y) % P;
}
for (int i = 1;i < m; i <<= 1)
for (int j = 0;j < m; j += (i << 1))
for (int k = 0;k < i; k++) {
ll x0 = dp[j+k][0], x1 = dp[j+k][1];
ll y0 = dp[i+j+k][0], y1 = dp[i+j+k][1];
dp[j+k][0] = x0 * y0 % P;
dp[j+k][1] = x1 * y1 % P;
dp[i+j+k][0] = x0 * y1 % P;
dp[i+j+k][1] = x1 * y0 % P;
}
for (int i = 0;i < m; i++) ans = (ans + dp[i][0]) % P;
write((ans * fpw(m, P - 2) % P + P - 1) % P);
return 0;
}