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+快速幂即可。
由于fwt和fft不同的是,卷积的长度是不变的。所以可以直接fwt后直接算出最后的答案,再做逆运算。
代码:
/**************************************************************
Problem: 4589
User: liangzihao
Language: C++
Result: Accepted
Time:8212 ms
Memory:3636 kb
****************************************************************/
#include <iostream>
#include <cstdio>
#include <cmath>
#define LL long long
const int maxn=1e5+7;
const LL mod=1e9+7;
const LL inv2=500000004;
using namespace std;
LL f[maxn],n;
LL prime[maxn],not_prime[maxn];
LL m,cnt,len;
void getprime(LL n)
{
for (LL i=2;i<=n;i++)
{
if (!not_prime[i])
{
prime[++cnt]=i;
}
for (LL j=1;j<=cnt;j++)
{
if (i*prime[j]>n) break;
not_prime[i*prime[j]]=1;
if (i%prime[j]==0) break;
}
}
}
void fwt(LL *a,LL l,LL r)
{
if (l==r) return;
LL n=(r-l+1)/2,mid=n+l;
fwt(a,l,mid-1);
fwt(a,mid,r);
for (LL i=l;i<mid;i++)
{
LL u=a[i],v=a[i+n];
a[i]=(u+v)%mod;
a[i+n]=(u+mod-v)%mod;
}
}
void dwt(LL *a,LL l,LL r)
{
if (l==r) return;
LL n=(r-l+1)/2,mid=n+l;
dwt(a,l,mid-1);
dwt(a,mid,r);
for (LL i=l;i<mid;i++)
{
LL u=a[i],v=a[i+n];
a[i]=(u+v)%mod*inv2%mod;
a[i+n]=(u+mod-v)%mod*inv2%mod;
}
}
LL power(LL x,LL y)
{
if (y==0) return 1;
if (y==1) return x;
LL c=power(x,y/2);
c=(c*c)%mod;
if (y%2) c=(c*x)%mod;
return c;
}
int main()
{
getprime(5e4);
while (scanf("%lld%lld",&n,&m)!=EOF)
{
len=1;
while (len<=m) len*=2;
for (LL i=0;i<len;i++) f[i]=0;
for (LL j=1;j<=cnt;j++)
{
if (prime[j]<=m) f[prime[j]]=1;
else break;
}
fwt(f,0,len-1);
for (LL i=0;i<len;i++) f[i]=power(f[i],n%mod);
dwt(f,0,len-1);
printf("%lld\n",f[0]);
}
}