4589: Hard Nim

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 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

Sample Output

6
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 }