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
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <math.h>
#include <vector>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=2e5+10;
int n,m;
ll a[maxn],rev;
int prime[maxn],tot;
bool isprime[maxn];
ll Pow(ll a,ll b){
ll ans=1;
while (b){
if (b&1)ans=ans*a%mod;
b>>=1;
a=a*a%mod;
}
return ans;
}
void init(){
rev=Pow(2,mod-2);
tot=0;
for (int i=2;i<=50000;i++){
if (!isprime[i]){
prime[tot++]=i;
}
for (int j=i+i;j<=50000;j+=i)isprime[j]=true;
}
//for (int i=0;i<15;i++)printf ("%d\n",prime[i]);
}
//n是2的冪次方
void FWT(ll a[],int n)
{
for(int d=1;d<n;d<<=1)
for(int m=d<<1,i=0;i<n;i+=m)
for(int j=0;j<d;j++){
int x=a[i+j],y=a[i+j+d];
a[i+j]=(x+y)%mod,a[i+j+d]=(x-y+mod)%mod;
//xor:a[i+j]=x+y,a[i+j+d]=(x-y+mod)%mod;
//and:a[i+j]=x+y;
//or:a[i+j+d]=x+y;
}
}
void UFWT(ll a[],int n)
{
for(int d=1;d<n;d<<=1)
for(int m=d<<1,i=0;i<n;i+=m)
for(int j=0;j<d;j++){
int x=a[i+j],y=a[i+j+d];
a[i+j]=1LL*(x+y)*rev%mod,a[i+j+d]=(1LL*(x-y)*rev%mod+mod)%mod;
//xor:a[i+j]=(x+y)/2,a[i+j+d]=(x-y)/2;
//and:a[i+j]=x-y;
//or:a[i+j+d]=y-x;
}
}
void solve(ll a[],int m,int n)
{
FWT(a,m);
for (int i=0;i<m;i++)a[i]=Pow(a[i],n);
UFWT(a,m);
}
int main()
{
init();
//printf ("%d\n",Pow(2,5));
while (scanf ("%d%d",&n,&m)!=EOF){
memset (a,0,sizeof (a));
int len=1;while (len<=m)len*=2;
for (int i=0;i<tot&&prime[i]<=m;i++){
a[prime[i]]++;
}
solve(a,len,n);
printf ("%lld\n",a[0]);
}
return 0;
}