BZOJ4589 Hard Nim

<body> <center><h1>4589: Hard Nim</h1><span class="green">Time Limit: </span>10 Sec&nbsp;&nbsp;<span class="green">Memory Limit: </span>128 MB<br><span class="green">Submit: </span>1888&nbsp;&nbsp;<span class="green">Solved: </span>1011<br>[<a href="submitpage.php?id=4589">Submit</a>][<a href="problemstatus.php?id=4589">Status</a>][<a href="bbs.php?id=4589">Discuss</a>]</center><h2>Description</h2><div class="content"><div></div> <div></div> <div>Claris和NanoApe在玩石子游戏,他们有n堆石子,规则如下:</div> <div>1. Claris和NanoApe两个人轮流拿石子,Claris先拿。</div> <div>2. 每次只能从一堆中取若干个,可将一堆全取走,但不可不取,拿到最后1颗石子的人获胜。</div> <div>不同的初始局面,决定了最终的获胜者,有些局面下先拿的Claris会赢,其余的局面Claris会负。</div> <div>Claris很好奇,如果这n堆石子满足每堆石子的初始数量是不超过m的质数,而且他们都会按照最优策略玩游戏,那么NanoApe能获胜的局面有多少种。</div> <div>由于答案可能很大,你只需要给出答案对10^9+7取模的值。</div> <div></div> <div></div> <p></p></div><h2>Input</h2><div class="content"><div>输入文件包含多组数据,以EOF为结尾。</div> <div>对于每组数据:</div> <div>共一行两个正整数n和m。</div> <div> <div>每组数据有1&lt;=n&lt;=10^9, 2&lt;=m&lt;=50000。</div> <div>不超过80组数据。</div> </div> <div></div> <p></p></div><h2>Output</h2><div class="content"><div></div> <div></div> <p></p></div><h2>Sample Input</h2> <div class="content"><span class="sampledata">3 7<br> 4 13</span></div><h2>Sample Output</h2> <div class="content"><span class="sampledata">6<br> 120</span></div><h2>HINT</h2> <div class="content"><p></p></div><h2>Source</h2> <div class="content"><p><a href="problemset.php?search=Topcoder SRM 518 Div1 Hard Nim By Tangjz">Topcoder SRM 518 Div1 Hard Nim By Tangjz</a></p></div> </body>

题解

将每堆石子数的可能情况当成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  阅读(96)  评论(0编辑  收藏  举报

导航