大致题意: (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;
}