【BZOJ4589】Hard Nim(FWT+快速幂)

点此看题面

大致题意: (nim)游戏,有(n)堆石子,每堆石子个数都是不超过(m)的质数,问后手能赢的方案数。

(nim)游戏+(FWT)

显然,根据(nim)游戏的结论,后手能赢意味着石子数异或和为(0)

考虑我们令(p_i)表示(i)是否为质数,假设当前只有两堆石子,可令:

[f_i=sum_{j xor k=i}p_j imes p_k ]

(f_0)就是答案。

容易发现,(j xor k=i),恰好是(FWT)中异或卷积的条件。

(n)堆石子,其实就是(n)(p)卷在一起,直接快速幂就行了。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define M 50000
#define P 65536
#define X 1000000007
#define I2 500000004
using namespace std;
int n,m,p[P],a[P],t[P];
I void FWT(int *s,CI op)//FWT
{
	for(RI i=1,j,k,x,y;i^P;i<<=1) for(j=0;j^P;j+=i<<1) for(k=0;k^i;++k) x=s[j+k],y=s[i+j+k],
		s[j+k]=(x+y)%X,s[i+j+k]=(x-y+X)%X,op&&(s[j+k]=1LL*s[j+k]*I2%X,s[i+j+k]=1LL*s[i+j+k]*I2%X);
}
I void Mul(int *x,int *y) {for(RI i=0;i^P;++i) x[i]=1LL*x[i]*y[i]%X;}//直接乘
I bool IsP(CI x) {for(RI i=2;i*i<=x;++i) if(!(x%i)) return 0;return 1;}//判断是否为质数
int main()
{
	RI i;for(i=2;i<=M;++i) p[i]=IsP(i);W(scanf("%d%d",&n,&m)==2)//预处理质数表
	{
		for(i=0;i^P;++i) a[i]=0,t[i]=1;for(i=1;i<=m;++i) a[i]=p[i];FWT(a,0);//预处理快速幂数组,并用FWT把它变换掉
		W(n) n&1&&(Mul(t,a),0),Mul(a,a),n>>=1;FWT(t,1),printf("%d
",t[0]);//快速幂,然后变回来输出
	}return 0;
}
原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ4589.html