BZOJ4589 Hard Nim
<body>
<center><h1>4589: Hard Nim</h1><span class="green">Time Limit: </span>10 Sec <span class="green">Memory Limit: </span>128 MB<br><span class="green">Submit: </span>1888 <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<=n<=10^9, 2<=m<=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]);
}
}
静渊以有谋,疏通而知事。