BZOJ4589: Hard Nim
BZOJ4589: Hard Nim
https://lydsy.com/JudgeOnline/problem.php?id=4589
分析:
- 根据博弈论的知识,这玩意先手必败的状态是异或和\(=0\)。
- 于是设\(f[i][j]\)表示前\(i\)个石子异或和为\(j\)的方案数。
- 转移乘上一个\(m\)以内的质数\(is[p]\)多项式。
- 答案就是\(is[p]^n\)这玩意显然可以快速幂,我们将它\(fwt\)之后对每一项进行快速幂再弄回去就好了。
代码:
#include<cstdio>
#define N 66650
#define o 1000000007
typedef long long ll;int u[N],i,j,k,t,l,n,m;ll A[N],v=(o+1)/2;ll q(ll x,ll y){ll r=1;for(;y;y>>=1,x=x*x%o)if(y&1)r=r*x%o;return r;}void f(ll *a,int l,int g){for(k=2;k<=l;k<<=1)for(t=k>>1,i=0;i<l;i+=k)for(j=i;j<i+t;j++){ll p=a[j+t];a[j+t]=(a[j]-p)%o;a[j]=(a[j]+p)%o;if(g^1)a[j]=a[j]*v%o,a[j+t]=a[j+t]*v%o;}}int main(){for(u[1]=u[0]=1,i=2;i<N;i++)for(j=i+i;j<N;j+=i)u[j]=1;while(scanf("%d%d",&n,&m)!=EOF){for(l=1;l<=m;l<<=1);for(i=0;i<l;i++)A[i]=(i<=m&&!u[i]);f(A,l,1);for(i=0;i<l;i++)A[i]=q(A[i],n);f(A,l,0);printf("%lld\n",(A[0]+o)%o);}}