【状压DP】BZOJ2734-[HNOI2012]集合选数

已经八月份了药丸,开始肝作业并且准备高考啦!!

【题目大意】

《集合论与图论》这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x 不能在该子集中。现在求以下问题:对于任意一个正整数 n≤100000,如何求出{1, 2,..., n} 的满足上述约束条件的子集的个数(只需输出对 1,000,000,001 取模的结果)(包括空集)。

【思路】

对于n以内任意与6互质的整数x,我们列出一个矩阵:

x 3x 9x 27x ...

2x 6x 18x 54x ...

4x 12x 36x 108x ...

所以我们现在枚举与6互质的这个数x,然后进行状态压缩的转移。这个有点类似于先前的king。f[i][j]表示到第i行,且第i行状态为j的总可能性。不过它并不一定是矩形,每一行的列数可能不同,对于某行列数为j,我们只需枚举0..2^j-1的状态,并记录为before转移到下一行DP。

这里用了滚动数组,不过不要忘记每次新的滚动数组都要清空一下。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define mod 1000000001
 6 using namespace std;
 7 typedef long long LL;
 8 const int MAXN=12;
 9 int n;
10 int usable[1<<MAXN],f[2][1<<MAXN];
11 bool mark[1<<MAXN];
12
13 int Usable(int x)
14 {
15     if (x<<1&x || x>>1&x) return 0;else return 1;
16 }
17
18 int dp(int now)
19 {
20     memset(f,0,sizeof(f));
21     int cur=0,before=-1;//before指上一行有几个数
22     for (int i=0;now*(1<<i)<=n;i++)//枚举每一行的第一个数,求出总的行数
23     {
24         cur=1-cur;
25         int tmp=now*(1<<i),j;
26         for (j=0;tmp<=n;j++,tmp*=3);//求出每一行有几个数
27         for (int k=0;k<(1<<j);k++)//枚举当前行的状态
28         {
29             f[cur][k]=0;//【不要忘记了初始化☆】
30             if (usable[k])
31             {
32                 if (before==-1) {f[cur][k]=1;continue;}//如果是第一行,则将可行状态设为1
33                 for (int p=0;p<(1<<before);p++)
34                     if (usable[p])
35                         if ((k&p)==0) f[cur][k]=f[cur][k]+f[1-cur][p],f[cur][k]%=mod;//这里不要忘记了也要mod
36             }
37         }
38         before=j;
39     }
40     int ans=0;
41     for (int i=0;i<(1<<before);i++) ans+=f[cur][i],ans%=mod;
42     return (ans);
43 }
44
45 void getusable()
46 {
47     memset(usable,0,sizeof(usable));
48     for (int i=0;i<(2<<MAXN);i++)
49         if (Usable(i)) usable[i]=1;
50 }
51
52 void solve()
53 {
54     memset(mark,0,sizeof(mark));
55     LL ans=1;//为了防止乘法的时候溢出,可以先用longlong,再转换回int
56     for (int i=1;i<=n;i++)
57         if ((i%2)&&(i%3)) ans=(ans*dp(i))%mod;
58     printf("%d\n",(int)ans);
59 }
60
61 int main()
62 {
63     scanf("%d",&n);
64     getusable();
65     solve();
66     return 0;
67 }
时间: 2024-08-02 15:02:51

【状压DP】BZOJ2734-[HNOI2012]集合选数的相关文章

[BZOJ2734][HNOI2012]集合选数

试题描述 <集合论与图论>这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以下条件的子集:若 x 在该子集中,则 2x 和 3x 不能在该子集中.同学们不喜欢这种具有枚举性质的题目,于是把它变成了以下问题:对于任意一个正整数 n≤100000,如何求出{1, 2,..., n} 的满足上述约束条件的子集的个数(只需输出对 1,000,000,001 取模的结果),现在这个问题就交给你了. 输入 只有一行,其中有一个正整数 n,30%的数据满足 n≤20. 输出 仅包

[BZOJ2734][HNOI2012] 集合选数(状态压缩+思维)

Description 题目链接 Solution 可以根据条件构造出一个矩阵, 1 3 9 27 81... 2 6 18.... 4 12 36... 这个矩阵满足\(G[i][1]=G[i-1][1]*2(1< i),G[i][j]=G[i][j-1]*3(1\leq i,1<j)\) 也就是要满足不能同时选择矩阵中\((G[i][j],G[i][j+1],G[i+1][j])\) 而且会发现,矩阵可能有多个,应枚举矩阵的\(G[1][1]\)并记录下出现过的数 这样会发现矩阵最大长为1

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

[HNOI2012]集合选数 题目描述 <集合论与图论>这门课程有一道作业题,要求同学们求出\({1,2,3,4,5}\)的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x 不能在该子集中. 同学们不喜欢这种具有枚举性 质的题目,于是把它变成了以下问题:对于任意一个正整数, 如何求出\({1,2,3...n}\) 的满足上述约束条件的子集的个数(只需输出对 \(10^{9}+1\) 取模的结果),现在这个问题就交给你了. 输入格式: 只有一行,其中有一个正整数 \(n\) 30

bzoj 2734: [HNOI2012]集合选数 状压DP

2734: [HNOI2012]集合选数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 560  Solved: 321[Submit][Status] Description <集合论与图论>这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x 不能在该子集中.同学们不喜欢这种具有枚举性 质的题目,于是把它变成了以下问题:对于任意一个正整数 n≤100000,如何

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

题意:<集合论与图论>这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x 不能在该子集中.同学们不喜欢这种具有枚举性 质的题目,于是把它变成了以下问题:对于任意一个正整数 n≤100000,如何求出{1, 2,..., n} 的满足上述约束条件的子集的个数(只需输出对 1,000,000,001 取模的结果),现在这个问题就 交给你了. 分析: 我们构造出一个矩阵 1 2^0*3^1 2^0*3^2 2^1*3^

bzoj 2734: [HNOI2012]集合选数

Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 779  Solved: 456[Submit][Status][Discuss] Description <集合论与图论>这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x 不能在该子集中.同学们不喜欢这种具有枚举性 质的题目,于是把它变成了以下问题:对于任意一个正整数 n≤100000,如何求出{1, 2,...,

[HNOI2012]集合选数

Description <集合论与图论>这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x 不能在该子集中.同学们不喜欢这种具有枚举性 质的题目,于是把它变成了以下问题:对于任意一个正整数 n≤100000,如何求出{1, 2,..., n} 的满足上述约束条件的子集的个数(只需输出对 1,000,000,001 取模的结果),现在这个问题就 交给你了. Input 只有一行,其中有一个正整数 n,30%的数据满

【BZOJ-2732】集合选数 状压DP (思路题)

2734: [HNOI2012]集合选数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1070  Solved: 623[Submit][Status][Discuss] Description <集合论与图论>这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x 不能在该子集中.同学们不喜欢这种具有枚举性 质的题目,于是把它变成了以下问题:对于任意一个正整数 n

bzoj2734【HNOI2012】集合选数

2734: [HNOI2012]集合选数 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 831  Solved: 487 [Submit][Status][Discuss] Description <集合论与图论>这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x 不能在该子集中.同学们不喜欢这种具有枚举性 质的题目,于是把它变成了以下问题:对于任意一个正整数