题目大意:在{1,2,3,…..,n}的集合中选出一个子集。
该子集满足一条约束条件:若x在该集合中,那么2*x以及3*x不能在这个集合中,求方案数模1000000001
题解:比较珂学的构造
黄学长题解
我的收获:23333
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
using namespace std;
#define N 100005
#define P 1000000001
int n,Canu;
int state[N];
long long ans=1;
long long num[20],f[20][2049];
bool vst[N];
inline bool ok(int x){return !(x&(x<<1));}
long long calc(int x)
{
int cnt=0;
memset(num,0,sizeof(num));
memset(f,0,sizeof(f));f[0][0]=1;
for(;x<=n;x*=2){
cnt++;
for(int tmp=x;tmp<=n;tmp*=3) num[cnt]++,vst[tmp]=1;
for(int i=1;i<=Canu;i++){
int si=state[i];
if(si>=(1<<num[cnt])) break;
for(int j=1;j<=Canu;j++){
int sj=state[j];
if(sj>=(1<<num[cnt-1])) break;
if(!(si&sj)) f[cnt][si]+=f[cnt-1][sj],f[cnt][si]%=P;
}
}
}
long long ret=0;
for(int i=0;i<(1<<num[cnt]);i++) ret+=f[cnt][i],ret%=P;
return ret;
}
void work()
{
scanf("%d",&n);
for(int i=0;i<(1<<11);i++) if(ok(i)) state[++Canu]=i;
for(int i=1;i<=n;i++) if(!vst[i]) ans*=calc(i),ans%=P;
printf("%lld\n",ans);
}
int main()
{
work();
return 0;
}