BZOJ4589 Hard Nim(博弈+FWT)
即使n个数的异或为0。如果只有两堆,将质数筛出来设为1,做一个异或卷积即可。显然这个东西满足结合律,多堆时直接快速幂。可以在点值表示下进行。
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; #define N (1<<17) #define P 1000000007 #define inv2 500000004 int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int T,n,m,f[N]; bool flag[N]; int ksm(int a,int k) { int s=1; for (;k;k>>=1,a=1ll*a*a%P) if (k&1) s=1ll*s*a%P; return s; } void FWT(int *a,int n,int op) { for (int i=2;i<=n;i<<=1) for (int j=0;j<n;j+=i) for (int k=j;k<j+(i>>1);k++) { int x=a[k],y=a[k+(i>>1)]; a[k]=(x+y)%P,a[k+(i>>1)]=(x-y+P)%P; if (op==1) a[k]=1ll*a[k]*inv2%P,a[k+(i>>1)]=1ll*a[k+(i>>1)]*inv2%P; } } int main() { #ifndef ONLINE_JUDGE freopen("bzoj4589.in","r",stdin); freopen("bzoj4589.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif flag[1]=flag[0]=1; for (int i=2;i<=50000;i++) for (int j=2;j<=50000/i;j++) flag[i*j]=1; while (scanf("%d %d",&n,&m)!=EOF) { int t=1;while (t<=m) t<<=1; for (int i=0;i<=m;i++) f[i]=flag[i]^1; for (int i=m+1;i<t;i++) f[i]=0; FWT(f,t,0); for (int i=0;i<t;i++) f[i]=ksm(f[i],n); FWT(f,t,1); cout<<f[0]<<endl; } }