本来是个水笔DP,40*1e6,不过我一直在往按位考虑的DP上想,当时也很困,然后队友一看,这不是FWT板题吗?就秒了= =
这题刚好n=40,于是就均分成两半,先2^20*20预处理一蛤两边的数组的方案数,然后fwt乘一蛤,就能知道每个异或值有多少种方案数。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=3e6+5;
int n,m,N,M;
LL cnta[maxn],cntb[maxn];
int a[maxn];
inline void FWT(LL a[],int n)
{
for(int d=1;d<n;d<<=1)
for(int m=d<<1,i=0;i<n;i+=m)
for(int j=0;j<d;++j)
{
LL x=a[i+j],y=a[i+j+d];
a[i+j]=(x+y),a[i+j+d]=(x-y);
}
}
inline void UFWT(LL a[],int n)
{
for(int d=1;d<n;d<<=1)
for(int m=d<<1,i=0;i<n;i+=m)
for(int j=0;j<d;++j)
{
LL x=a[i+j],y=a[i+j+d];
a[i+j]=(x+y)/2,a[i+j+d]=(x-y)/2;
}
}
int main(){
int _;
scanf("%d",&_);
int cas=1;
while(_--){
int r=0;
scanf("%d%d",&n,&m);
for(int i=0;i<n;++i){
scanf("%d",a+i);
if(r<a[i])r=a[i];
}
int mx=1;
for(;mx<=r;mx<<=1);
memset(cnta,0,sizeof(LL)*(mx+1));
memset(cntb,0,sizeof(LL)*(mx+1));
N=n/2,M=n-N;
int tot=1<<N;
for(int i=0;i<tot;++i){
int val=0;
for(int j=0;j<N;++j)
if(i&(1<<j)){
val^=a[j];
}
++cnta[val];
}
tot=1<<M;
for(int i=0;i<tot;++i){
int val=0;
for(int j=0;j<M;++j)
if(i&(1<<j)){
val^=a[N+j];
}
++cntb[val];
}
FWT(cnta,mx);
FWT(cntb,mx);
for(int i=0;i<mx;++i)cnta[i]=cnta[i]*cntb[i];
UFWT(cnta,mx);
LL ans=0;
for(int i=m;i<mx;++i)ans+=cnta[i];
printf("Case #%d: %lld\n",cas++,ans);
}
return 0;
}
#include<cstdio>
#include<cstring>
#define maxl 1<<20
int n,m,cas;
int a[maxl];
long long f[45][maxl];
inline void prework()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=0;j<maxl;j++)
f[i][j]=0;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
}
inline void mainwork()
{
f[1][0]=1;f[1][a[1]]=1;
for(int i=2;i<=n;i++)
for(int j=0;j<maxl;j++)
f[i][j]=f[i-1][j]+f[i-1][j^a[i]];
}
inline void print()
{
long long ans=0;
for(int i=m;i<maxl;i++)
ans+=f[n][i];
printf("Case #%d: %lld\n",cas,ans);
}
int main()
{
int t;
scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}