2734: [HNOI2012]集合选数
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 993 Solved: 589
[ Submit][ Status][ Discuss]
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 个集合满足要求,分别是空集,{1},{1,4},{2},{2,3},{3},{3,4},{4}。
HINT
Source
解题思路:完全不会,只好看答案了。
答案的思路很巧妙。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int n,tail,tail1,lon,height;
long long ans;
bool b[100001];
const int MOD=1000000001;
int t[100001];
int q[3000],qg[3000];
int dis[19][2100];
int ch[20][13];
inline int read()
{
char y; int x=0,f=1; y=getchar();
while (y<'0' || y>'9') {if (y=='-') f=-1; y=getchar();}
while (y>='0' && y<='9') {x=x*10+int(y)-48; y=getchar();}
return x*f;
}
void yu(int now,int sum)
{
if (now>lon)
{
dis[1][sum]=1; ++tail; q[tail]=sum; return;
}
yu(now+1,sum);
yu(now+2,sum+(1<<(now-1)));
}
void dfs(int opp,int now,int sum)
{
if (ch[opp][now]==false)
{
++tail1; qg[tail1]=sum; return;
}
dfs(opp,now+1,sum);
dfs(opp,now+2,sum+(1<<(now-1)));
}
int main()
{
n=read();
memset(b,true,sizeof(b));
ans=1;
for (int i=1;i<=n;++i)
if (b[i])
{
b[i]=false;
int now=i;
memset(ch,false,sizeof(ch)); height=0;
while (now<=n)
{
++height; t[height]=now; b[now]=false;
now=now*2;
}
lon=0;
for (int j=1;j<=height;++j)
{
int hide=1; int og=t[j];
while (og<=n)
{
ch[j][hide]=true; b[og]=false;
og=og*3; ++hide;
}
lon=max(lon,hide-1);
}
memset(dis,0,sizeof(dis)); tail=0;
if (height==1)
{
ans=ans*2%MOD;
}
yu(1,0);
for (int j=2;j<=height;++j)
{
tail1=0;
dfs(j,1,0);
for (int k=1;k<=tail;++k)
for (int h=1;h<=tail1;++h)
if ((q[k]+qg[h])==(q[k]|qg[h]))
{
dis[j][qg[h]]=(dis[j][qg[h]]+dis[j-1][q[k]])%MOD;
}
tail=tail1; long long opp=0;
for (int k=1;k<=tail1;++k)
{
q[k]=qg[k];
if (j==height) opp=(opp+dis[j][qg[k]])%MOD;
}
if (j==height) ans=ans*opp%MOD;
}
}
printf("%lld",ans);
}