2020牛客暑期多校第二场E-Exclusive OR(FWT)
CSDN食用链接:https://blog.csdn.net/qq_43906000/article/details/107929968
题目大意:给你n个数,\(a_i(0\leq a_i<2^{18})\),你现在需要选出其中\(1,2,3,....n\)个数,使得其\(a_1\bigoplus a_2\bigoplus ...\bigoplus a_i\)的值最大。\(1\leq n\leq 2\times 10^5\)
输入
4
1 4 5 7
输出
7 6 7 7
说明
\({i = 1 : 7 = 7}\)
\(i = 2 : 7\oplus 1 = 6\)
\(i = 3 : 7\oplus 1 \oplus 1 = 7\)
\(i = 4 : 7\oplus 1 \oplus 4 \oplus 5 = 7\)
对于只取一个数的情况我们很容易知道它是个什么状态,那么取两个数的情况一定是再取一个的基础上再取一个的,取三个数的情况是在取两个数的情况下再取一个的...依此类推,那么我们就大概可以得到第\(i\)个状态是由第\(i-1,1\)两个转移过来的。
那么我们用\(f_1[x]\)表示只取一个数的时候\(x\)是否存在,那么我们对于第\(i\)个数判断\(x\)是否存在的时候就是去看看是否有\(f_{i-1},f_1\)的某两位数相异或等于\(x\)。那么很明显,我们不能直接枚举,那么做个式子过来就是\(f_i[x]=\sum_{y\otimes z=x}f_{i-1}[y]f_1[z]\)那么我们就可以发现这是个异或卷积。。。我们每次取的时候卷一下就好了,但取的次数有\(n\)次,那么如果每一次都卷的话,复杂度就是\(nwlog(w)\),\(w\leq2^{18}\)。。然后就会发现直接爆炸!
所以我们必须要优化时间,实际上对于\(i>19\)的情况我们可以直接计算,并不需要进行卷积,首先对于\(\forall i\in N^+,ans_{}\geq ans_{i-2}\),因为只需要再\(a_i\)的基础上任意取一个数两次就可以满足了,如果\(i>19\)后有\(ans_{i}>ans_{i-2}\)那么也就是说必须要\(i-1\)个数才能满秩,而这里的\(i-1\)至少为19,而题目的数据只有\(18\),所以矛盾了,即\(ans_{i}=ans_{i-2}\)
那么我们只需要对前\(19\)个数进行卷积就OK了。
以下是AC代码:
#include <bits/stdc++.h>
using namespace std;
const int mac=3e5+10;
const int mod=998244353;
namespace FWT{
const int MOD=998244353;
inline int FAdd(const int &a,const int &b){return a+b>=MOD? a+b-MOD:a+b;}
inline int FSub(const int &a,const int &b){return a-b<0? a-b+MOD:a-b;}
inline int FMul(const int &a,const int &b){return 1ll*a*b%MOD;}
inline int FPow(int a,int b){int ret=1;while(b){if(b&1)ret=FMul(ret,a);a=FMul(a,a);b>>=1;}return ret;}
const int INV2=FPow(2,MOD-2);
void FWTOR(int *ary,const int &len,const int &typ){
for(int L=2,T=1;L<=len;L<<=1,T<<=1)
for(int i=0;i<len;i+=L)
for(int j=i;j<i+T;j++)
if(typ==1) ary[j+T]=FAdd(ary[j+T],ary[j]);
else ary[j+T]=FSub(ary[j+T],ary[j]);
}
void FWTAND(int *ary,const int &len,const int &typ){
for(int L=2,T=1;L<=len;L<<=1,T<<=1)
for(int i=0;i<len;i+=L)
for(int j=i;j<i+T;j++)
if(typ==1) ary[j]=FAdd(ary[j],ary[j+T]);
else ary[j]=FSub(ary[j],ary[j+T]);
}
void FWTXOR(int *ary,const int &len,const int &typ){
for(int L=2,T=1;L<=len;L<<=1,T<<=1)
for(int i=0;i<len;i+=L)
for(int j=i;j<i+T;j++){
int Aj=ary[j];
ary[j]=FAdd(Aj,ary[j+T]);
ary[j+T]=FSub(Aj,ary[j+T]);
if(typ==-1)
ary[j]=FMul(ary[j],INV2),ary[j+T]=FMul(ary[j+T],INV2);
}
}
}
int f[22][mac],ans[mac];
int fcp[mac],f1[mac];
int main(int argc, char const *argv[])
{
int n,mx,nw=0;
scanf ("%d",&n);
for (int i=1; i<=n; i++){
int x;
scanf ("%d",&x);
ans[1]=max(ans[1],x); fcp[x]=1;
f1[x]=1; nw=max(x,nw);
}
mx=1;
while (mx<=nw) mx<<=1;
int typefront=1,typeback=-1;
for (int i=2; i<=19; i++){
for (int j=0; j<=mx; j++) f[1][j]=fcp[j];
FWT::FWTXOR(f[1],mx,typefront);
if (i!=2) FWT::FWTXOR(f[i-1],mx,typefront);
else FWT::FWTXOR(f1,mx,typefront);
if (i!=2) for (int j=0; j<=mx; j++) f[i][j]=1LL*f[1][j]*f[i-1][j]%mod;
else for (int j=0; j<=mx; j++) f[i][j]=1LL*f[1][j]*f1[j]%mod;
FWT::FWTXOR(f[i],mx,typeback);
for (int j=0; j<=mx; j++)
if (f[i][j]) ans[i]=j;
}
for (int i=20; i<=n; i++) ans[i]=ans[i-2];
for (int i=1; i<=n; i++) printf("%d ",ans[i]); printf("\n");
return 0;
}