BZOJ4589: Hard Nim【FWT+DP】
4589: Hard Nim
【题目描述】
【题解】
长度为n的不大于m的素数序列亦或和为0的方案数。
考虑DP:^
显然只有为素数是其余等于0。
对于以上式子,就是一个典型的FWT形式。
先对求FWT(),然后每一位快速幂,在UFWT()回来即可。
【代码如下】
#include<cstdio>
#include<cstring>
using namespace std;
const int MOD=1e9+7;
int n,m,F[1<<16],INV;
int qsm(int x,int b){
int Mul=1;
for(;b;b>>=1,x=1ll*x*x%MOD) if(b&1) Mul=1ll*Mul*x%MOD;
return Mul;
}
void FWT(int Len){
for(int Step=1;Step<Len;Step<<=1)
for(int i=0;i<Len;i+=(Step<<1))
for(int j=0;j<Step;j++){
int x=F[i+j],y=F[i+j+Step];
F[i+j]=(x+y)%MOD;F[i+j+Step]=(x-y+MOD)%MOD;
}
}
void UFWT(int Len){
for(int Step=1;Step<Len;Step<<=1)
for(int i=0;i<Len;i+=(Step<<1))
for(int j=0;j<Step;j++){
int x=F[i+j],y=F[i+j+Step];
F[i+j]=1ll*(x+y)*INV%MOD;F[i+j+Step]=(1ll*(x-y)*INV%MOD+MOD)%MOD;
}
}
int main(){
INV=qsm(2,MOD-2);
for(int Len;~scanf("%d%d",&n,&m);){
memset(F,0,sizeof(F));F[0]=F[1]=1;
for(int i=1;i<=m;i++) if(!F[i])
for(int j=(i<<1);j<=m;j+=i) F[j]=1;
for(int i=0;i<=m;i++) F[i]^=1;
for(Len=1;Len<=m;Len<<=1);
FWT(Len);
for(int i=0;i<Len;i++) F[i]=qsm(F[i],n);
UFWT(Len);
printf("%d\n",F[0]);
}
return 0;
}