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

来源:互联网 发布:照片生成视频软件 编辑:程序博客网 时间:2024/06/01 12:28

一道不错的套路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 1000000001using 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
原创粉丝点击