[HNOI2012]集合選數(狀壓DP+構造)

題目要求若出現x,則不能出現2x,3xc++

因此咱們考慮構造一個矩陣spa

\(1\ 2\ 4 \ 8……\)debug

\(3\ 6\ 12\ 24……\)code

\(9\ 18\ 36……\)get

\(……\)it

不難發現,對於一個矩陣,若我選擇了一個數x,則在矩陣內該數的相鄰格子都不能選,題目就被轉化成了玉米田了,能夠用狀壓DP解決class

可是直接作是不對的,好比5就沒有出如今這個序列中原理

因此咱們能夠構造多個矩陣,用乘法原理統計答案便可file

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define re register
#define debug printf("Now is Line : %d\n",__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;
}
相關文章
相關標籤/搜索