bzoj4589 Hard Nim

Description

Claris和NanoApe在玩石子游戏,他们有n堆石子,规则如下:
1. Claris和NanoApe两个人轮流拿石子,Claris先拿。
2. 每次只能从一堆中取若干个,可将一堆全取走,但不可不取,拿到最后1颗石子的人获胜。
不同的初始局面,决定了最终的获胜者,有些局面下先拿的Claris会赢,其余的局面Claris会负。
Claris很好奇,如果这n堆石子满足每堆石子的初始数量是不超过m的质数,而且他们都会按照最优策略玩游戏,那么NanoApe能获胜的局面有多少种。
由于答案可能很大,你只需要给出答案对10^9+7取模的值。

Input

输入文件包含多组数据,以EOF为结尾。
对于每组数据:
共一行两个正整数n和m。
每组数据有1<=n<=10^9, 2<=m<=50000。
不超过80组数据。

Output

Sample Input

3 7
4 13

Sample Output

6
120

 

正解:$FWT$。

背了一下板子。。

这个东西可以用来求$C=A\otimes B$,其中$C_{i}=\sum_{j \otimes k=i}a_{j}b_{k}$。

然后大概就是一些逻辑运算符,比如说与,或,异或什么的。。

写了个板子在下面,上面$3$种情况都列举了。不过为什么是对的。。

 

  1 //It is made by wfj_2048~
  2 #include <algorithm>
  3 #include <iostream>
  4 #include <cstring>
  5 #include <cstdlib>
  6 #include <cstdio>
  7 #include <vector>
  8 #include <cmath>
  9 #include <queue>
 10 #include <stack>
 11 #include <map>
 12 #include <set>
 13 #define rhl (1000000007)
 14 #define inf (1<<30)
 15 #define il inline
 16 #define RG register
 17 #define ll long long
 18 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
 19 
 20 using namespace std;
 21 
 22 int f[150010],a[150010],vis[100010],prime[100010],N,n,m,cnt,inv;
 23 
 24 il int gi(){
 25     RG int x=0,q=1; RG char ch=getchar();
 26     while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
 27     if (ch=='-') q=-1,ch=getchar();
 28     while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
 29     return q*x;
 30 }
 31 
 32 il ll qpow(RG ll a,RG ll b){
 33     RG ll ans=1;
 34     while (b){
 35     if (b&1) ans=ans*a%rhl;
 36     a=a*a%rhl,b>>=1;
 37     }
 38     return ans;
 39 }
 40 
 41 il void sieve(){
 42     for (RG int i=2;i<=50000;++i){
 43     if (!vis[i]) prime[++cnt]=i;
 44     for (RG int j=1,k;j<=cnt;++j){
 45         k=i*prime[j]; if (k>50000) break;
 46         vis[k]=1; if (i%prime[j]==0) break;
 47     }
 48     }
 49     return;
 50 }
 51 
 52 il void fwt(int *a,RG int n){
 53     for (RG int i=1;i<n;i<<=1)
 54     for (RG int j=0;j<n;j+=(i<<1))
 55         for (RG int k=0,x,y;k<i;++k){
 56         x=a[j+k],y=a[j+k+i];
 57         a[j+k]=x+y; if (a[j+k]>=rhl) a[j+k]-=rhl;
 58         a[j+k+i]=x-y; if (a[j+k+i]<0) a[j+k+i]+=rhl;
 59         //and:a[j+k]=x+y;
 60         //or:a[j+k+i]=x+y;
 61         //xor:a[j+k]=x+y,a[j+k+i]=x-y;
 62         }
 63     return;
 64 }
 65 
 66 il void ufwt(int *a,RG int n){
 67     for (RG int i=1;i<n;i<<=1)
 68     for (RG int j=0;j<n;j+=(i<<1))
 69         for (RG int k=0,x,y;k<i;++k){
 70         x=a[j+k],y=a[j+k+i];
 71         a[j+k]=(int)((ll)inv*(ll)(x+y)%rhl);
 72         a[j+k+i]=(int)((ll)inv*(ll)(x-y+rhl)%rhl);
 73         //and:a[j+k]=x-y;
 74         //or:a[j+k+i]=y-x;
 75         //xor:a[j+k]=(x+y)/2,a[j+k+i]=(x-y)/2;
 76         }
 77     return;
 78 }
 79 
 80 il void work(){
 81     if (n==1){ puts("0"); return; }
 82     for (N=1;N<=m;N<<=1); memset(a,0,sizeof(a));
 83     for (RG int i=1;i<=cnt && prime[i]<=m;++i) a[prime[i]]=1;
 84     memset(f,0,sizeof(f)),f[0]=1,fwt(f,N),fwt(a,N);
 85     while (n){
 86     if (n&1){
 87         for (RG int i=0;i<N;++i) f[i]=(int)((ll)f[i]*(ll)a[i]%rhl);
 88     }
 89     for (RG int i=0;i<N;++i) a[i]=(int)((ll)a[i]*(ll)a[i]%rhl);
 90     n>>=1;
 91     }
 92     ufwt(f,N); printf("%d\n",f[0]); return;
 93 }
 94 
 95 int main(){
 96     File("hardnim");
 97     sieve(),inv=qpow(2,rhl-2);
 98     while (scanf("%d%d",&n,&m)!=EOF) work();
 99     return 0;
100 }

 

posted @ 2017-06-21 13:24  wfj_2048  阅读(342)  评论(0编辑  收藏