zoukankan      html  css  js  c++  java
  • BZOJ 2734: [HNOI2012]集合选数( 状压dp )

    1 3 9 ……

    2 6 18……

    4 12 36……

    把数写成上面的样子,那么就变成了给出若干个类似矩阵的东西, 然后求任意一行r的任意一个元素c与r-1,r,r+1行的c-1,c+1不能同时被选中..就是一个状态压缩的dp.dp(x, s)表示第x行, 这一行状态为s的方案数.最后乘法原理乘一下。

    ----------------------------------------------------------------------------------

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
     
    using namespace std;
     
    typedef long long ll;
    #define b(i) (1 << (i))
     
    const int MAXR = 18;
    const int MAXC = 12;
    const int maxn = 100009;
    const int MOD = 1000000001;
     
    int N, n, ans, dp[MAXR][b(MAXC)], A[MAXR][MAXC], len[MAXR];
    bool F[maxn];
     
    inline void upd(int &t, int v) {
    if((t += v) >= MOD) t -= MOD;
    }
     
    void Calculate() {
    int cnt = 0;
    for(int i = b(len[0]); i--; )
    dp[0][i] = !(i & (i >> 1));
    for(int i = 1; i < n; i++) {
    memset(dp[i], 0, sizeof dp[i]);
    for(int s = b(len[i]); s--; )
    for(int ps = b(len[i - 1]); ps--; )
    if(!(s & (s >> 1)) && !(s & ps))
    upd(dp[i][s], dp[i - 1][ps]);
    }
    for(int s = b(len[--n]); s--; )
    upd(cnt, dp[n][s]);
    ans = ll(ans) * cnt % MOD;
    }
     
    int main() {
    scanf("%d", &N);
    memset(F, 0, sizeof F);
    ans = 1;
    for(int i = 1; i <= N; i++) if(!F[i]) {
    F[A[0][0] = i] = 1;
    n = 0;
    for(int &j = n; ; j++) {
    len[j] = 1;
    for(int &k = len[j]; ; k++) if(A[j][k - 1] * 3 <= N) {
    F[A[j][k] = A[j][k - 1] * 3] = true;
    } else
    break;
    if(A[j][0] << 1 > N) break;
    F[A[j + 1][0] = A[j][0] << 1] = true;
    }
    n++;
    Calculate();
    }
    printf("%d ", ans);
    return 0;
    }

    ----------------------------------------------------------------------------------

    2734: [HNOI2012]集合选数

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

    HINT

    Source

  • 相关阅读:
    UVa
    UVa 1630
    P3891 [GDOI2014]采集资源
    一个非常naive的小学数学魔术证明题
    P2831 [NOIP2016 提高组] 愤怒的小鸟
    P4211 [LNOI2014]LCA
    P4137 Rmq Problem / mex 强制在线做法
    P2272 [ZJOI2007]最大半连通子图
    P5664 [CSP-S2019] Emiya 家今天的饭
    盘点linux操作系统中的10条性能调优命令,一文搞懂Linux系统调优
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/5013969.html
Copyright © 2011-2022 走看看