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)的主要内容,如果未能解决你的问题,请参考以下文章

[HNOI2012]集合选数 --- 状压DP

BZOJ_2734_[HNOI2012]集合选数_构造+状压DP

HDU4057 Rescue the Rabbit(AC自动机+状压DP)

POJ1699 Best Sequence(AC自动机+状压DP)

集合划分(状压DP)

lightoj1037_状压dp