bzoj4589 FWT xor版本
4589: Hard Nim
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 865 Solved: 484
[Submit][Status][Discuss]
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
4 13
Sample Output
6
120
120
HINT
Source
Topcoder SRM 518 Div1 Hard Nim By Tangjz
这题是一个NIM游戏,根据结论,先手输的情况只有所有的石子数xor起来的数为0
https://blog.csdn.net/jr_mz/article/details/51606673
这个blog比我自己瞎比比好多了。
1 #include<cstring> 2 #include<cmath> 3 #include<iostream> 4 #include<algorithm> 5 #include<cstdio> 6 7 #define N 50007 8 #define ll long long 9 #define P 1000000007 10 #define inv 500000004 11 using namespace std; 12 inline int read() 13 { 14 int x=0,f=1;char ch=getchar(); 15 while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} 16 while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} 17 return x*f; 18 } 19 20 int n,m,len,num; 21 ll A[(1<<18)+5],B[(1<<18)+5]; 22 int pri[N],np[N]; 23 24 void FWT(ll *a,int flag) 25 { 26 ll x,y; 27 for (int h=1;h<len;h<<=1) 28 for(int j=0;j<len;j+=(h<<1)) 29 for(int k=j;k<j+h;k++) 30 { 31 if (flag==1) x=a[k],y=a[k+h],a[k]=(x+y)%P,a[k+h]=(x-y+P)%P; 32 else x=a[k],y=a[k+h],a[k]=(x+y)*inv%P,a[k+h]=((x-y)*inv%P+P)%P; 33 } 34 } 35 void pow(ll *a,ll y) 36 { 37 ll *b=B;b[0]=1; 38 FWT(a,1),FWT(b,1); 39 while(y) 40 { 41 if(y&1) for(int i=0;i<len;i++) b[i]=a[i]*b[i]%P; 42 for(int i=0;i<len;i++) 43 a[i]=a[i]*a[i]%P; 44 y>>=1; 45 } 46 FWT(b,-1); 47 } 48 int main() 49 { 50 for(int i=2;i<=50000;i++) 51 { 52 if(!np[i]) pri[++num]=i; 53 for(int j=1;j<=num&&i*pri[j]<=50000;j++) 54 { 55 np[i*pri[j]]=1; 56 if(i%pri[j]==0) break; 57 } 58 } 59 while(~scanf("%d%d",&n,&m)) 60 { 61 for(len=1;len<=m;len<<=1); 62 memset(A,0,sizeof(A)); 63 memset(B,0,sizeof(B)); 64 for(int i=1;i<=num&&pri[i]<=m;i++) 65 A[pri[i]]=1; 66 pow(A,n); 67 printf("%lld\n",B[0]); 68 } 69 }