BZOJ4589: Hard Nim【FWT+DP】

25 篇文章 0 订阅
2 篇文章 0 订阅

4589: Hard Nim

【题目描述】

传送门

【题解】

长度为n的不大于m的素数序列亦或和为0的方案数。

考虑DP: F [ i ] [ x F[i][x F[i][x^ y ] = F [ i − 1 ] [ x ] ∗ F [ 1 ] [ y ] y]=F[i-1][x]*F[1][y] y]=F[i1][x]F[1][y]

显然 F [ 1 ] [ i ] F[1][i] F[1][i]只有 i i i为素数是 F [ 1 ] [ i ] = 1 F[1][i]=1 F[1][i]=1其余等于0。

对于以上式子,就是一个典型的FWT形式。

先对 F [ 1 ] F[1] F[1]求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;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值