zoukankan      html  css  js  c++  java
  • [HNOI2012]集合选数(状压DP+构造)

    题目要求若出现x,则不能出现2x,3x

    所以我们考虑构造一个矩阵

    (1 2 4 8……)

    (3 6 12 24……)

    (9 18 36……)

    (……)

    不难发现,对于一个矩阵,若我选择了一个数x,则在矩阵内该数的相邻格子都不能选,题目就被转化成了玉米田了,可以用状压DP解决

    但是直接做是不对的,比如5就没有出现在这个序列中

    所以我们可以构造多个矩阵,用乘法原理统计答案即可

    #include<bits/stdc++.h>
    using namespace std;
    #define il inline
    #define re register
    #define debug printf("Now is Line : %d
    ",__LINE__)
    #define file(a) freopen(#a".in","r",stdin);//freopen(#a".out","w",stdout)
    #define int long long
    #define inf 123456789
    #define mod 1000000001
    il int read() {
        re int x = 0, f = 1; re char c = getchar();
        while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar();}
        while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
        return x * f;
    }
    #define rep(i, s, t) for(re int i = s; i <= t; ++ i)
    #define drep(i, s, t) for(re int i = t; i >= s; -- i)
    #define mem(k, p) memset(k, p, sizeof(k))
    #define maxn 100005
    int n, m, a[20][20], g[1 << 15], vis[maxn], H, L[20], dp[20][1 << 15], ans = 1;
    il void martix(int x) {
        H = 0;
        rep(i, 1, 18) {
            a[i][1] = (i == 1) ? x : a[i - 1][1] * 2;
            if(a[i][1] > n) break;
            ++ H, L[i] = vis[a[i][1]] = 1;
            rep(j, 2, 11) {
                a[i][j] = a[i][j - 1] * 3;
                if(a[i][j] > n) break;
                L[i] = j, vis[a[i][j]] = 1;
            }
        }
    }
    il int solve() {
        rep(i, 0, (1 << L[1]) - 1) dp[1][i] = g[i];
        rep(i, 2, H) {
            rep(j, 0, (1 << L[i]) - 1) {
                if(!g[j]) continue;
                dp[i][j] = 0;
                rep(k, 0, (1 << L[i - 1]) - 1) {
                    if(g[k] && (k & j) == 0) dp[i][j] += dp[i - 1][k];
                }
            }
        }
        int t = 0;
        rep(i, 0, (1 << L[H]) - 1) t = (t + dp[H][i]) % mod;
        return t;
    }
    signed main() {
        n = read();
        rep(i, 0, (1 << 11) - 1) g[i] = !(i & (i << 1));
        rep(i, 1, n) if(!vis[i]) martix(i), ans = ans * solve() % mod;
        printf("%lld", ans);
        return 0;
    }
    
  • 相关阅读:
    DELLR720 独立显卡DVI转VGA问题
    淘宝开源项目之Tsar
    remmina rdp远程连接windows
    linux 下查看硬件信息(mac,IP地址,硬盘型号,序列号等)
    Ubuntu16.04下安装googlechrome flash 插件和安装网易云音乐
    Linux实现crontab每秒秒执行
    Supervisord
    es 加磁盘扩容
    通知神器——java调用钉钉群自定义机器人
    python 退出程序的方式
  • 原文地址:https://www.cnblogs.com/bcoier/p/10788835.html
Copyright © 2011-2022 走看看