「NowCoder Contest 295」H. Playing games
还是见的题太少了
「NowCoder Contest 295」H. Playing games
题意:选出尽量多的数使得异或和为$ 0$
$ Solution:$
问题等价于选出尽量少的数使得异或和为全集
根据线性基思想可以推得整个集合的异或集合可以被不超过$ bitcount$个数的异或集合表示
因此答案也不超过$ bitcount$
对于原集合我们做若干次$ FWT$
每次把当前异或集合卷上初始集合
复杂度$ O(n \ log^2 \ n)$
足以通过本题
但是还不够
我们发现我们只是想知道$ FWT$数组中某一位上的值
设$ f’$是数组$ f$的$FWT$数组
有$ f_S=\frac{1}{2^n} \sum\limits f'_T(-1)^{|S\cap T|}$
这样我们只需要初始对原数组$ FWT$一次
期间一直用点值表达式进行计算
然后单词$ O(n)$验证即可
时间复杂度:$ O(n \ log \ n)$
$ my \ code$
#include<ctime> #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<queue> #define p 998244353 #define rt register int #define ll long long using namespace std; inline ll read(){ ll x = 0; char zf = 1; char ch = getchar(); while (ch != '-' && !isdigit(ch)) ch = getchar(); if (ch == '-') zf = -1, ch = getchar(); while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); return x * zf; } void write(ll y){if(y<0)putchar('-'),y=-y;if(y>9)write(y/10);putchar(y%10+48);} void writeln(const ll y){write(y);putchar('\n');} int i,j,k,m,n,x,y,z,cnt,invn; int ksm(int x,int y){ int ans=1; for(rt i=y;i;i>>=1,x=1ll*x*x%p)if(i&1)ans=1ll*x*ans%p; return ans; } void FWT(int n,int *A,int fla){ for(rt i=1;i<n;i<<=1) for(rt j=0;j<n;j+=i<<1) for(rt k=0;k<i;k++){ const int x=A[j+k],y=A[i+j+k]; A[j+k]=(x+y)%p,A[i+j+k]=(x-y)%p; } if(fla==-1)for(rt i=0;i<n;i++)A[i]=1ll*A[i]*invn%p; } int a[524299],b[524299]; int main(){ n=read();int s=0; for(rt i=1;i<=n;i++){ x=read();s^=x; a[x]=1; } int lim=524288;invn=ksm(lim,p-2); a[0]=1;FWT(lim,a,-1); for(rt i=0;i<lim;i++)b[i]=1; for(rt i=0;i<=20;i++){ ll ans=0; for(rt j=0;j<lim;j++)if(__builtin_popcount(j&s)&1)ans+=b[j];else ans-=b[j]; if(ans%p){ cout<<n-i; break; } for(rt j=0;j<lim;j++)b[j]=1ll*a[j]*b[j]%p; } return 0; }