[HNOI2012]集合选数

题目描述

《集合论与图论》这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x 不能在该子集中。

同学们不喜欢这种具有枚举性 质的题目,于是把它变成了以下问题:对于任意一个正整数 n<=100000,如何求出{1, 2,..., n} 的满足上述约束条件的子集的个数(只需输出对 1,000,000,001 取模的结果),现在这个问题就 交给你了。

输入输出格式

输入格式:

只有一行,其中有一个正整数 n,30%的数据满足 n<=20。

输出格式:

仅包含一个正整数,表示{1, 2,..., n}有多少个满足上述约束条件 的子集。

输入输出样例

输入样例#1: 复制
输出样例#1: 复制
每个k(不含2,3的因数)可以单独考虑,答案是所有k方案的积
即考虑$k*2^i*3^j<=n$的方案
构造一个矩阵:
 k   3k  9k  27k
2k  6k  18k  54k
4k 12k  36k 108k
令f[i][S]表示当前选到2^i,行状态为S
S第j位为1表示选了2^i*3^j
首先根据题意,S相邻2位不能为1
然后转移时前面的状态S'
要满足与S&S'=0
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 using namespace std;
 7 int n,Log2[100001],Log3[100001],pw2[21],pw3[21];
 8 int ans,Mod=1e9+1,f[21][100001],s[100001],cnt,p,q,sum;
 9 int main()
10 {int i,j,k,l;
11   cin>>n;
12   Log2[1]=0;
13   for (i=2;i<=n;i++)
14     Log2[i]=Log2[i/2]+1;
15   Log3[1]=0;
16   for (i=3;i<=n;i++)
17     Log3[i]=Log3[i/3]+1;
18   pw2[0]=1;
19   for (i=1;i<=18;i++)
20     pw2[i]=pw2[i-1]*2;
21   pw3[0]=1;
22   for (i=1;i<=13;i++)
23     pw3[i]=pw3[i-1]*3;
24   for (i=0;i<pw2[13];i++)
25     {
26       s[i]=1;
27       for (j=0;j<=11;j++)
28     if ((i&pw2[j])&&(i&pw2[j+1])) s[i]=0;
29     }
30   ans=1;
31   for (i=1;i<=n;i++)
32     if (i%2&&i%3)
33     {
34       k=1;
35       q=Log3[n/i]+1;
36       for (j=0;j<pw2[q];j++)
37     f[0][j]=s[j];
38       while (i*pw2[k]<=n)
39     {
40       p=Log3[n/(i*pw2[k])]+1;
41       for (j=0;j<pw2[p];j++)
42         if (s[j])
43         {
44           f[k][j]=0;
45           for (l=0;l<pw2[q];l++)
46         if (s[l]&&((j&l)==0))
47           {
48             f[k][j]=(f[k][j]+f[k-1][l])%Mod;
49           }
50         }
51         else f[k][j]=0;
52       q=p;
53       k++;
54     }
55       sum=0;
56       for (j=0;j<pw2[q];j++)
57     sum=(sum+f[k-1][j])%Mod;
58       ans=(1ll*ans*sum)%Mod;
59     }
60   cout<<ans;
61 }

 

posted @ 2018-03-09 08:24  Z-Y-Y-S  阅读(308)  评论(0编辑  收藏  举报