BZOJ2734: [HNOI2012]集合选数
2734: [HNOI2012]集合选数
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 505 Solved: 287
[Submit][Status]
Description
《集合论与图论》这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x 不能在该子集中。同学们不喜欢这种具有枚举性 质的题目,于是把它变成了以下问题:对于任意一个正整数 n≤100000,如何求出{1, 2,..., n} 的满足上述约束条件的子集的个数(只需输出对 1,000,000,001 取模的结果),现在这个问题就 交给你了。
Input
只有一行,其中有一个正整数 n,30%的数据满足 n≤20。
Output
仅包含一个正整数,表示{1, 2,..., n}有多少个满足上述约束条件 的子集。
Sample Input
4
Sample Output
8
【样例解释】
有8 个集合满足要求,分别是空集,{1},{1,4},{2},{2,3},{3},{3,4},{4}。
【样例解释】
有8 个集合满足要求,分别是空集,{1},{1,4},{2},{2,3},{3},{3,4},{4}。
HINT
Source
题解:
不能再神的做法。。。
1 3 9
2 6 18
。。。。
然后就转化成了不能选两个相邻的数的方案数了。。。状压搞定
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<iostream> 7 #include<vector> 8 #include<map> 9 #include<set> 10 #include<queue> 11 #include<string> 12 #define inf 1000000000 13 #define maxn 100000+100 14 #define maxm 500+100 15 #define eps 1e-10 16 #define ll long long 17 #define pa pair<int,int> 18 #define mod 1000000001 19 using namespace std; 20 inline int read() 21 { 22 int x=0,f=1;char ch=getchar(); 23 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 24 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 25 return x*f; 26 } 27 int n,num[20]; 28 ll f[20][1<<12]; 29 bool v[maxn]; 30 ll get(int x) 31 { 32 int m=0; 33 memset(num,0,sizeof(num)); 34 memset(f,0,sizeof(f)); 35 f[0][0]=1; 36 while(x<=n) 37 { 38 m++; 39 int xx=x; 40 while(xx<=n) 41 { 42 num[m]++;v[xx]=1;xx*=3; 43 } 44 for(int i=0;i<1<<num[m];i++) 45 { 46 int j; 47 for(j=1;j<num[m];j++)if((i&(1<<(j-1)))&&(i&(1<<j)))break; 48 if(j!=num[m])continue; 49 for(j=0;j<1<<num[m-1];j++)if(!(i&j))f[m][i]=(f[m][i]+f[m-1][j])%mod; 50 } 51 x*=2; 52 } 53 ll t=0; 54 for(int i=0;i<1<<num[m];i++)t=(t+f[m][i])%mod; 55 return t; 56 } 57 int main() 58 { 59 freopen("input.txt","r",stdin); 60 freopen("output.txt","w",stdout); 61 n=read(); 62 ll ans=1; 63 for(int i=1;i<=n;i++)if(!v[i])ans=(ans*get(i))%mod; 64 printf("%lld\n",ans); 65 return 0; 66 }
UPD:我说我的程序怎么跑得贼慢。。。就因为我每次就memset吗?。。。
还有一个就是判断 i 中是否有两个连续的1,只要判断 i&(i<<1)是否为0即可