Live2D

题解 黎明前的巧克力

题目传送门

题目大意

初始有两个数 \(a,b\) ,有 \(n\) 次操作,每次提供一个数 \(a_i\) ,要么不操作,要么从 \(a,b\) 中选一个数异或上 \(a_i\) ,问最后 \(a,b\) 相同的方案数。

\(n,a_i\le 10^6\)

思路

不难看出如果我们设 \(x=a\oplus b\) ,那么每次操作就是 \(x\gets x\oplus a_i\) ,于是我们可以想到使用 \(\texttt{FWT}\) 解决这个问题。我们发现最后的答案其实就是:

\[[x^0]\bigoplus_{i=1}^{n}(1+2x^{a_i})-1 \]

(减 \(1\) 是因为题目要求不能不操作,尽管这显得非常多此一举)

然后我们就发现直接 \(\texttt{FWT}\) 铁定 gg ,然后我们考虑到有值得数位很少,可以联想到 CF1119H Triple ,我们发现 \(\texttt{FWT}[i]\) 要么为 \(-1\) 要么为 \(3\) ,因为 \(1\) 产生的贡献一定为 \(1\) ,而 \(2x^{a_i}\) 产生的贡献一定为 \(\pm 2\)

于是,我们的问题就是对于每一位知道有多少个 \(3\) (因为 \(3\) 的个数和 \(-1\) 的个数之和一定为 \(n\))。我们设这个东西为 \(x\) ,我们发现如果设

\[f_i=\texttt{FWT}(\sum_{i=1}^{n}(1+2x^{a_i}))[i] \]

那我们就有等式:

\[(-x)+3(n-x)=f_i \]

于是我们就可以解出 \(x\) 了 。然后我们将这个东西带回去,\(\texttt{IDWT}\) 一遍就好了。

时间复杂度 \(\Theta(n\log^2 n)\),假设 \(n\) 与值域同阶。

\(\texttt{Code}\)

#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define mod 998244353
#define MAXN 1048576

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}

int n,maxf,inv2,inv4,logn,g[MAXN],aa[MAXN],pw[MAXN];
int mul (int a,int b){return 1ll * a * b % mod;}
int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
int qkpow (int a,int b){
	int res = 1;for (;b;b >>= 1,a = mul (a,a)) if (b & 1) res = mul (res,a);
	return res;
}

void FWT (int *f,int n){
	for (Int i = 1;i < n;i <<= 1)
		for (Int j = 0;j < n;j += i << 1)
			for (Int k = 0;k < i;++ k){
				int x = f[j + k],y = f[i + j + k];
				f[j + k] = add (x,y),f[i + j + k] = dec (x,y);
			} 
}

void IFWT (int *f,int n){
	for (Int i = 1;i < n;i <<= 1)
		for (Int j = 0;j < n;j += i << 1)
			for (Int k = 0;k < i;++ k){
				int x = f[j + k],y = f[i + j + k];
				f[j + k] = mul (inv2,add (x,y)),f[i + j + k] = mul (inv2,dec (x,y));
			} 
}

signed main(){
	read (n),pw[0] = 1;
	inv2 = qkpow (2,mod - 2),inv4 = qkpow (4,mod - 2);
	for (Int i = 1;i <= n;++ i) pw[i] = mul (pw[i - 1],3); 
	for (Int i = 1,ai;i <= n;++ i) read (ai),g[0] ++,g[ai] += 2,maxf = max (maxf,ai);
	while ((1 << logn) <= maxf) logn ++;
	FWT (g,1 << logn);
	for (Int i = 0;i < 1 << logn;++ i) {
		int x = mul (dec (3 * n,g[i]),inv4);
		g[i] = mul (x & 1 ? (mod - 1) : 1,pw[n - x]);
	}
	IFWT (g,1 << logn);
	write (dec (g[0],1)),putchar ('\n');
 	return 0;
}
posted @ 2020-08-20 16:13  Dark_Romance  阅读(119)  评论(0编辑  收藏  举报