• BZOJ2734: [HNOI2012]集合选数


    2734: [HNOI2012]集合选数

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 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}。

    HINT

     

    Source

    题解:
    不能再神的做法。。。
    1 3 9 
    2 6 18
    。。。。
    然后就转化成了不能选两个相邻的数的方案数了。。。状压搞定
    代码:
     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
    ",ans);
    65     return 0;
    66 }
    View Code

     UPD:我说我的程序怎么跑得贼慢。。。就因为我每次就memset吗?。。。

    还有一个就是判断 i 中是否有两个连续的1,只要判断 i&(i<<1)是否为0即可

  • 相关阅读:
    web服务器iis安全设置
    Log explorer for sql server
    C#将image中的显示的图片转换成二进制
    .Net平台开发的技术规范与实践精华总结
    .net面试题整理
    Javascript 刷新框架及页面的方法总集
    WEB程序代码优化入手的几方面
    用js控制网页播放器
    SQL Server2000中死锁经验总结
    专家谈CSS设计
  • 原文地址:https://www.cnblogs.com/zyfzyf/p/3942386.html
Copyright © 2020-2023  润新知