【BZOJ 2734】[HNOI2012]集合选数 状压dp

236 篇文章 0 订阅
4 篇文章 0 订阅

一道不错的套路dp,首先构造矩阵,左上角为最小没有出现的数字,然后向右*3向下*2,这样只要不选相邻的数字就可以了,然后发现矩阵式log级的,状压dp莽一波。

最开始写出来10s卡过,后来看了一下被人的优化:

1.对于每一行预处理出合法的状态用flag标记

2.构造新的矩阵做dp的时候每一行一行的memset,不要一次直接写完(特别坑),否则会重复赋值很多用不上的空间

#include<cstdio>
#include<cstring>
#include<iostream>
#define LL long long
#define maxn 100020
#define Mod 1000000001
using namespace std;
bool vis[maxn],flag[1<<12];
int n,cnt[22];LL f[22][1<<12];

LL solve(int x){
	LL ans=0;int p=0;
	f[0][0]=1;
	while(x<=n){
		cnt[++p]=0;int tmp=x;
		memset(f[p],0,sizeof(f[p]));
		while(tmp<=n){cnt[p]++,vis[tmp]=true;tmp*=3;}
		for(int i=0;i< 1<<cnt[p];i++)if(flag[i]){
			for(int j=0;j< 1<<cnt[p-1];j++)if(flag[j]&&!(j&i))
				f[p][i]=(f[p][i]+f[p-1][j])%Mod;
		}
		x*=2;
	}
	for(int i=0;i< 1<<cnt[p];i++)if(flag[i])ans=(ans+f[p][i])%Mod;
	return ans;
}

int main(){
	scanf("%d",&n);LL ans=1;
	for(int i=0;i<1<<12;i++)
		if(!(i<<1&i))flag[i]=true;
	for(int i=1;i<=n;i++)if(!vis[i])ans=ans*solve(i)%Mod;
	printf("%lld",ans);
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值