BZOJ4589 Hard Nim

4589: Hard Nim

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

题解

将每堆石子数的可能情况当成01生成函数,那么要求的就是这些级数的异或卷积。

做FWT后快速幂即可。\(O(m\log m+m\log n)\)

#include<bits/stdc++.h>
#define co const
#define il inline
using namespace std;
typedef long long LL;

co int mod=1000000000+7;
il int add(int a,int b){
	return (a+=b)>=mod?a-mod:a;
}
il int mul(int a,int b){
	return (LL)a*b%mod;
}
int fpow(int a,int b){
	int ans=1;
	for(;b;b>>=1,a=mul(a,a))
		if(b&1) ans=mul(ans,a);
	return ans;
}

co int M=50000+10;
int v[M],p[M],tot;
co int N=65536+10;
int n,m,f[N];
int main(){
	p[0]=p[1]=1;
	for(int i=2;i<M;++i){
		if(!v[i]) p[++tot]=i;
		for(int j=1;j<=tot&&i*p[j]<M;++j){
			v[i*p[j]]=1;
			if(i%p[j]==0) break;
		}
	}
	while(~scanf("%d%d",&n,&m)){
		int len=ceil(log2(m+1)),lim=1<<len;
		fill(f,f+lim,0);
		for(int i=2;i<=m;++i)if(!v[i]) f[i]=1;
		for(int i=0;i<len;++i)
			for(int u=(lim-1)^(1<<i),j=u;;j=(j-1)&u){
				int l=f[j],r=f[j^(1<<i)];
				f[j]=add(l,r),f[j^(1<<i)]=add(l,mod-r);
				if(j==0) break;
			}
		for(int i=0;i<lim;++i) f[i]=fpow(f[i],n);
		for(int i=0;i<len;++i)
			for(int u=(lim-1)^(1<<i),j=u;;j=(j-1)&u){
				int l=f[j],r=f[j^(1<<i)];
				f[j]=add(l,r),f[j^(1<<i)]=add(l,mod-r);
				if(j==0) break;
			}
		for(int i=0;i<lim;++i) f[i]=mul(f[i],fpow(lim,mod-2));
		printf("%d\n",f[0]);
	}
}

posted on 2019-07-12 14:27  autoint  阅读(56)  评论(0编辑  收藏

导航