Description
Claris和NanoApe在玩石子游戏,他们有n堆石子,规则如下:
- Claris和NanoApe两个人轮流拿石子,Claris先拿。
- 每次只能从一堆中取若干个,可将一堆全取走,但不可不取,拿到最后1颗石子的人获胜。
不同的初始局面,决定了最终的获胜者,有些局面下先拿的Claris会赢,其余的局面Claris会负。
Claris很好奇,如果这n堆石子满足每堆石子的初始数量是不超过m的质数,而且他们都会按照最优策略玩游戏,那么NanoApe能获胜的局面有多少种。
由于答案可能很大,你只需要给出答案对10^9+7取模的值。
1<=n<=10^9, 2<=m<=50000。
不超过80组数据。
Solution
水题。。设f[i,j]表示第i轮异或出j的方案数,FWT转移套一个快速幂就可以了
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
#define copy(x,t) memcpy(x,t,sizeof(x))
const int MOD=1000000007;
const int ny2=MOD+1>>1;
const int N=131078;
int a[N],b[N],p[N];
bool np[N];
void FWT(int *a,int n,int f) {
for (int i=1;i<n;i<<=1) {
for (int j=0;j<n;j+=(i<<1)) {
for (int k=0;k<i;++k) {
int u=a[j+k],v=a[j+k+i];
a[j+k]=(u+v)%MOD,a[j+k+i]=(u-v+MOD)%MOD;
if (f==-1) {
a[j+k]=1LL*a[j+k]*ny2%MOD;
a[j+k+i]=1LL*a[j+k+i]*ny2%MOD;
}
}
}
}
}
void pre(int n) {
for (int i=2;i<=n;++i) {
if (!np[i]) p[++p[0]]=i;
for (int j=1;i*p[j]<=n&&j<=p[0];++j) {
np[i*p[j]]=1;
if (i%p[j]==0) break;
}
}
}
int main(void) {
pre(N-5);
for (int n,m;~scanf("%d%d",&n,&m);) {
fill(a,0);
for (int i=1;i<=p[0]&&p[i]<=m;++i) {
a[p[i]]=1;
}
int len=1;
for (;len<=m;len<<=1);
m=len;
FWT(a,m,1);
copy(b,a);
for (n--;n;n>>=1) {
if (n&1) for (int i=0;i<m;++i) b[i]=1LL*b[i]*a[i]%MOD;
for (int i=0;i<m;++i) a[i]=1LL*a[i]*a[i]%MOD;
}
FWT(b,m,-1);
printf("%d\n", b[0]);
}
return 0;
}