牛客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;
}
posted @ 2020-07-30 14:49  Hs-black  阅读(133)  评论(0编辑  收藏  举报