• 集合选数


    集合选数

    题目描述

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

    输入

    输入文件input.txt 只有一行,其中有一个正整数n,30%的数据满足n≤20。

    输出

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

    样例输入

    4

    样例输出

    8

    提示

    【样例解释】

    有8 个集合满足要求,分别是空集,{1},{1,4},{2},{2,3},{3},{3,4},{4}。


    solution

    神题,想不到

    如果当前一个数为x,把x*2^p*3^q 都抓出来,当成一个集合

    1x 3x  9x 27x 81x
    2x 6x 18x . .
    4x 12x . . .
    8x . . . .
    16x . . . .

    类似这样构出一个矩阵

    不同的矩阵之间互不影响

    那么我们肯定是要在矩阵中选若干个数,使得任意两列都不相邻

    注意到列数少只有11 ,可以状压dp解决

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define maxn 100005
    #define ll long long
    #define mod 1000000001
    using namespace std;
    int n,flag[maxn],Max[22];
    ll ans=0,a[20][20],f[20][maxn];
    ll work(int k){
        int M;
        for(int i=0;i<19;i++){
            int t=(k*(1<<i));
            if(t>n){M=i;break;}
            for(int j=0,now=1;j<19;j++,now*=3){
                a[i][j]=t*now;
                //cout<<i<<' '<<j<<' '<<a[i][j]<<endl;
                if(a[i][j]>n)break;
            }
        }
        for(int i=0;i<M;i++){
            Max[i]=0;
            for(int j=0;j<19;j++){
                if(a[i][j]>n)break;
                if(!flag[a[i][j]])flag[a[i][j]]=1;
                Max[i]+=(1<<j);
            }
        }
        for(int i=0;i<=M;i++)
        for(int j=0;j<=Max[i];j++)f[i][j]=0;
        for(int j=0;j<=Max[0];j++)if(!(j&(j<<1)))f[0][j]=1;
        for(int l=0;l<M;l++){
            for(int i=0;i<=Max[l];i++){
            for(int j=0;j<=Max[l+1];j++){
                if((!(i&j))&&!(j&(j<<1))){
                    f[l+1][j]=(f[l+1][j]+f[l][i])%mod;
                }
            }
            }
        }
        return f[M][0];
    }
    int main()
    {
        cin>>n;
        ans=1;
        for(int i=1;i<=n;i++)if(!flag[i])ans=(ans*work(i))%mod;
        cout<<ans<<endl;
        
  • 相关阅读:
    Dom解析
    几道算法水题
    Bom和Dom编程以及js中prototype的详解
    sqlserver练习
    java框架BeanUtils及路径问题练习
    Java的IO以及线程练习
    在数据库查询时解决大量in 关键字的方法
    SaltStack--配置管理
    SaltStack--远程执行
    SaltStack--快速入门
  • 原文地址:https://www.cnblogs.com/liankewei/p/10358757.html
Copyright © 2020-2023  润新知