bzoj4589 Hard Nim

传送门

分析

我们已知所有堆的异或和为0是后手必胜

我们又知道只有一堆时只有异或和为质数的情况为1其它为0

又因为ans[k][i^j] = ans[k-1][i] * ans[k-1][j]

所以直接fwt即可

我们可以对a数组fwt后用快速幂取它的n次方,然后再ifwt回来即可

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
const int mod = 1e9+7;
int n,m,N,a[200100],p[50010],cnt,inv;
bool is[50010];
inline int pw(int x,int p){
    int res=1;
    while(p){
      if(p&1)res=1ll*res*x%mod;
      x=1ll*x*x%mod;
      p>>=1;
    }
    return res;
}
inline void prework(){
    inv=pw(2,mod-2);
    for(int i=2;i<50000;i++)
      if(!is[i]){
          p[++cnt]=i;
          for(int j=i;j<=50000;j+=i)is[j]=1;
      }
}
inline void init(){
    memset(a,0,sizeof(a));
    n=1;
    while(n<=m)n<<=1;
    for(int i=1;i<=cnt&&p[i]<=m;i++)a[p[i]]=1;
}
inline void fwt(int a[],int f){
    int i,j,k;
    for(i=1;i<n;i<<=1)
      for(j=0;j<n;j+=(i<<1))
        for(k=0;k<i;k++){
          int x=a[j+k],y=a[i+j+k];
          a[j+k]=(x+y)%mod,a[i+j+k]=(x+mod-y)%mod;
          if(f==-1)a[j+k]=1ll*a[j+k]*inv%mod,a[i+j+k]=1ll*a[i+j+k]*inv%mod;
        }
}
int main(){
    int i,j,k;
    prework();
    while(scanf("%d%d",&N,&m)!=EOF){
      init();
      fwt(a,1);
      for(i=0;i<n;i++)a[i]=pw(a[i],N);
      fwt(a,-1);
      printf("%d\n",a[0]);
    }
    return 0;
}
posted @ 2019-03-10 22:25  水题收割者  阅读(106)  评论(0编辑  收藏