zoukankan      html  css  js  c++  java
  • 状压DP BZOJ2734 [HNOI2012]集合选数

    2734: [HNOI2012]集合选数

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 1388  Solved: 820
    [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

    【样例解释】

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

    写出如下矩阵

    1 3  9  27…

    2 6 18 54…

    4 12 36 108…

    发现最多有11列,我们在其中选取一些数,相邻的不能选择,然后就可以状压求方案数了;

    但是5没有出现,同样5的倍数也没有出现,7也如此……应该记录哪些数字出现过,没出现过就作为矩阵的第一个元素,最后把若干个矩阵的方案相乘即可。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 const long long mod=1000000001;
     7 long long ans;
     8 int n;
     9 int st[20],jz[20][20],g[20],f[20][5000];
    10 bool check[100010];
    11 int work(int x){
    12     memset(g,0,sizeof(g));
    13     jz[1][1]=x;
    14     for(int i=2;i<=18;i++)
    15         if(jz[i-1][1]*2<=n) jz[i][1]=jz[i-1][1]*2;
    16         else jz[i][1]=n+1;
    17     for(int i=1;i<=18;i++)
    18         for(int j=2;j<=18;j++)
    19             if(jz[i][j-1]*3<=n) jz[i][j]=jz[i][j-1]*3;
    20             else jz[i][j]=n+1;
    21     for(int i=1;i<=18;i++)
    22         for(int j=1;j<=18;j++)
    23             if(jz[i][j]<=n){
    24                 check[jz[i][j]]=1;
    25                 g[i]+=st[j-1];
    26             }
    27     for(int i=0;i<=18;i++)
    28         for(int j=0;j<=g[i];j++) f[i][j]=0;
    29     f[0][0]=1;
    30     for(int i=0;i<18;i++)
    31         for(int j=0;j<=g[i];j++)
    32             if(f[i][j])
    33                 for(int k=0;k<=g[i+1];k++)
    34                     if(!(j&k)&&!(k&(k>>1)))    f[i+1][k]=(f[i][j]+f[i+1][k])%mod;
    35     return f[18][0];
    36 } 
    37 int main(){
    38     scanf("%d",&n);
    39     st[0]=1;
    40     for(int i=1;i<=19;i++) st[i]=st[i-1]<<1;
    41     ans=1;
    42     for(int i=1;i<=n;i++)
    43         if(!check[i]) ans=(ans*(long long)work(i))%mod;
    44     printf("%lld",ans);
    45     return 0;
    46 }
  • 相关阅读:
    mybatis的mapper特殊字符转移以及动态SQL条件查询
    MySQL查询结果集字符串操作之多行合并与单行分割
    MySQL查询之内连接,外连接查询场景的区别与不同
    SpringBoot异步使用@Async原理及线程池配置
    SpringBoot 属性配置文件数据注入配置和yml与properties区别
    MySQL实战45讲第33讲
    Beta冲刺第1次
    Beta冲刺第5次
    Beta冲刺第4次
    Beta冲刺第3次
  • 原文地址:https://www.cnblogs.com/zwube/p/7261088.html
Copyright © 2011-2022 走看看