B - 集合选数 (状压DP)
Posted letlifestop
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了B - 集合选数 (状压DP)相关的知识,希望对你有一定的参考价值。
题目链接:https://cn.vjudge.net/contest/281960#problem/B
题目大意:中文题目
具体思路:
我们通过构造矩阵,
x , 3x,9x,27x
2x,6x,18x,54x
............
讲的很好的一篇博客:https://www.cnblogs.com/ljh2000-jump/p/6489018.html
可以看出,只要是选出的是相邻的,就一定是不满足的情况,所以说,我们可以通过构造矩阵将不满足的情况找出来,然后通过状压DP,通过不满足情况的筛选,将满足的情况找出来。
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 # define inf 0x3f3f3f3f 4 # define ll long long 5 const int maxn = 1e5+100; 6 const int mod = 1e9+1; 7 int vis[maxn]; 8 int a[20][20],n; 9 int f[20][maxn]; 10 int bin[20],b[20]; 11 int cal(int t) 12 { 13 memset(b,0,sizeof(b)); 14 a[1][1]=t; 15 for(int i=1; i<=18; i++) 16 { 17 if(a[i][1]*2<=n) 18 { 19 a[i+1][1]=a[i][1]*2; 20 } 21 else 22 { 23 a[i+1][1]=n+1; 24 } 25 } 26 for(int i=1; i<=18; i++) 27 { 28 for(int j=2; j<=11; j++) 29 { 30 if(a[i][j-1]*3<=n) 31 { 32 a[i][j]=a[i][j-1]*3; 33 } 34 else 35 a[i][j]=n+1; 36 } 37 } 38 for(int i=1; i<=18; i++) 39 { 40 for(int j=1; j<=11; j++) 41 { 42 if(a[i][j]<=n) 43 { 44 b[i]+=bin[j-1]; 45 vis[a[i][j]]=1; 46 } 47 } 48 } 49 for(int i=0; i<=18; i++) 50 { 51 for(int j=0; j<=b[i]; j++) 52 { 53 f[i][j]=0; 54 } 55 } 56 f[0][0]=1; 57 for(int i=0; i<=18; i++) 58 { 59 for(int j=0; j<=b[i]; j++) 60 { 61 if(f[i][j]) 62 { 63 for(int k=0; k<=b[i+1]; k++) 64 { 65 if(((j&k)==0)&&(k&(k>>1))==0) 66 { 67 f[i+1][k]=(f[i][j]+f[i+1][k])%mod; 68 } 69 } 70 } 71 } 72 } 73 return f[18][0]; 74 } 75 int main() 76 { 77 scanf("%d",&n); 78 bin[0]=1; 79 for(int i=1; i<=20; i++) 80 { 81 bin[i]=bin[i-1]<<1; 82 } 83 ll ans=1; 84 for(int i=1; i<=n; i++) 85 { 86 if(vis[i]) 87 continue; 88 ans=ans*cal(i)%mod; 89 } 90 printf("%lld ",ans); 91 return 0; 92 }
以上是关于B - 集合选数 (状压DP)的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ_2734_[HNOI2012]集合选数_构造+状压DP
HDU4057 Rescue the Rabbit(AC自动机+状压DP)