Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 2057 Solved: 1099
[Submit][Status][Discuss]
Description
Claris和NanoApe在玩石子游戏,他们有n堆石子,规则如下:
Input
输入文件包含多组数据,以EOF为结尾。
对于每组数据:
共一行两个正整数n和m。
每组数据有1<=n<=10^9, 2<=m<=50000。
不超过80组数据。
Output
Sample Input
3 7
4 13
Sample Output
6
120
其实不难发现可以把题目转化为:n个数字,每个数字为小于等于m的质数,问总体异或为0的方案数。
就是一个简单的NIM博弈。
但是怎么求异或为0的方案数呢?FWT+生成函数。
答案就为 FWT多项式的 n-1 次幂,然后 x的0次方 的系数。
但是n很大,不能n次FWT,所以套个快速幂即可。
虽然东西比较多,但是都是比较简单的知识点,没什么深的运用。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include
//#define int long long
using namespace std;
const int N=5e4+10,mod=1e9+7;
int n,m,lim,vis[N],inv2=5e8+4;
int a[1<<16],b[1<<16];
void get(int n){
vis[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i]){
for(int j=i+i;j<=n;j+=i) vis[j]=1;
}
}
}
inline void FWT(int *a,int flag){
for(int i=2;i<=lim;i<<=1)
for(int p=i>>1,j=0;j<lim;j+=i)
for(int k=j;k<j+p;k++){
int x=a[k],y=a[k+p];
a[k]=(x+y)%mod,a[k+p]=(x-y+mod)%mod;
if(flag==-1) a[k]=1LL*a[k]*inv2%mod,a[k+p]=1LL*a[k+p]*inv2%mod;
}
}
void qmi(int *a,int *b,int k){
FWT(a,1); FWT(b,1);
while(k){
if(k&1) for(int i=0;i<lim;i++) a[i]=1LL*a[i]*b[i]%mod;
for(int i=0;i<lim;i++) b[i]=1LL*b[i]*b[i]%mod;
k>>=1;
}
FWT(a,-1);
}
signed main(){
get(5e4);
while(cin>>n>>m){
for(lim=1;lim<=m;lim<<=1);
memset(a,0,sizeof a),memset(b,0,sizeof b);
for(int i=1;i<=m;i++) if(!vis[i]) a[i]=b[i]=1;
qmi(a,b,n-1);
printf("%d\n",a[0]);
}
return 0;
}