hdu6578 2019湖南省賽D題Modulo Nine 經典dp

@

題目

在這裏插入圖片描述

在這裏插入圖片描述


第一題題意是一共有{0,1,2,3}四種數字供選擇,問有多少個長度爲n的序列滿足所有m個條件,每個條件是說區間[L,R]內必須有恰好x個不同的數字。

第二題題意是10個數字供選擇,問有多少個長度爲n的序列滿足所有m個條件,每個條件是說區間[L,R]數字的乘積必須是9的倍數。

解析

  • hdu6578
  • \(dp[t][i][j][k]\)表示填完前\(t\)個位置,{\(0,1,2,3\)}中出現的數字最後一次出現的位置排序後爲\(t,i,j,k(t\gt i\gt j\gt k)\)的方案數。\(0\)表示數字未出現。
  • 枚舉四種轉移:
  • \(t-1\)位置的數字:\(dp[t][i][j][k]\)
  • \(i\)位置的數字:\(dp[t][t-1][j][k]\)
  • \(j\)位置的數字:\(dp[t][t-1][i][k]\)
  • \(k\)位置的數字:\(dp[t][t-1][i][j]\)
  • 但是不是所有轉移都有效,所以要枚舉限制條件,將不合法的轉移pass掉
  • 枚舉所有終點在\(t\)點的限制條件,將不合法的轉移的\(dp\)值歸零。
  • 時間複雜度:\(O(n^4)\),滾動數組優化空間複雜度:\(O(n^3)\)

  • 2019湖南省賽D題Modulo Nine
  • 關於乘積是否是9的倍數,這裏只有3類數字,0和9表示兩個3,3和6表示一個3,其他表示零個3
  • \(dp[t][i][j]\)表示填完前\(t\)個位置,最後一個3在\(i\),倒數第二個3在\(j\)的方案數。
  • 枚舉3種轉移:
  • \(0或9\)\(dp[t][t][t]\)
  • \(3或6\)\(dp[t][t][i]\)
  • 填其他數字:\(dp[t][i][j]\)
  • 但是不是所有轉移都有效,所以要枚舉限制條件,將不合法的轉移pass掉
  • 枚舉所有終點在\(t\)點的限制條件,將不合法的轉移的\(dp\)值歸零。
  • 時間複雜度:\(O(n^3)\),滾動數組優化空間複雜度:\(O(n^2)\)

兩題思路一模一樣,是一種很經典的dp。

AC_Code

hdu6578
const int mod = 998244353;
const int MXN = 1e5 + 7;
const int MXE = 2e5 + 7;

int n, m, c;
vector<pii> mp[MXN];
LL dp[2][101][101][101];
void get_dp() {
    dp[c][0][0][0] = 1;
    for(int t = 1; t <= n; ++t) {
        c ^= 1;
        for(int i = 0; i <= t; ++i) for(int j = 0; j <= i; ++j) for(int k = 0; k <= j; ++k) dp[c][i][j][k] = 0;
        for(int i = 0; i < t; ++i) for(int j = 0; j <= i; ++j) for(int k = 0; k <= j; ++k) {
            if((i != j && j != k) || k == 0) {
                dp[c][i][j][k] = (dp[c][i][j][k] + dp[c ^ 1][i][j][k]) % mod;
                dp[c][t - 1][j][k] = (dp[c][t - 1][j][k] + dp[c ^ 1][i][j][k]) % mod;
                dp[c][t - 1][i][j] = (dp[c][t - 1][i][j] + dp[c ^ 1][i][j][k]) % mod;
                dp[c][t - 1][i][k] = (dp[c][t - 1][i][k] + dp[c ^ 1][i][j][k]) % mod;
            }
        }
        for(int h = 0; h < (int)mp[t].size(); ++h) {
            int l = mp[t][h].fi, x = mp[t][h].se;
            for(int i = 0; i < t; ++i) for(int j = 0; j <= i; ++j) for(int k = 0; k <= j; ++k) {
                int cnt = 1;
                if(i >= l) ++ cnt;
                if(j >= l) ++ cnt;
                if(k >= l) ++ cnt;
                if(cnt != x) dp[c][i][j][k] = 0;
            }
        }
    }
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("/home/cwolf9/CLionProjects/ccc/in.txt", "r", stdin);
    //freopen("/home/cwolf9/CLionProjects/ccc/out.txt", "w", stdout);
#endif
    int tim = read();
    while(tim --) {
        n = read(), m = read();
        for(int i = 1, a, b, c; i <= m; ++i) {
            a = read(), b = read(), c = read();
            mp[b].eb(mk(a, c));
        }
        get_dp();
        LL ans = 0;
        for(int i = 0; i < n; ++i)
            for(int j = 0; j <= i; ++j)
                for(int k = 0; k <= j; ++k) if((i != j && j != k) || k == 0) ans = (ans + dp[c][i][j][k]) % mod;
        printf("%lld\n", (ans+mod)%mod);
    }
#ifndef ONLINE_JUDGE
    cout << "time cost:" << clock() << "ms" << endl;
#endif
    return 0;
}
2019省賽D
const int mod = 1e9 + 7;
const int MXN = 1e5 + 7;
const int MXE = 2e5 + 7;

int n, m, c;
int mp[MXN];
LL dp[2][101][101];
void get_dp() {
    clr(dp, 0);
    dp[c][0][0] = 1;
    for(int t = 1; t <= n; ++t) {
        c ^= 1;
        for(int i = 0; i <= t; ++i) for(int j = 0; j <= i; ++j) dp[c][i][j] = 0;
        for(int i = 0; i <= t; ++i) {
            for(int j = 0; j <= i; ++j) {
                dp[c][i][j] = (dp[c][i][j] + dp[c^1][i][j] * 6) % mod;
                dp[c][t][i] = (dp[c][t][i] + dp[c^1][i][j] * 2) % mod;
                dp[c][t][t] = (dp[c][t][t] + dp[c^1][i][j] * 2) % mod;
            }
        }
        if(mp[t] == -1) continue;
        for(int i = 0; i <= t; ++i) {
            for(int j = 0; j <= i; ++j) {
                if(i < mp[t] || j < mp[t]) dp[c][i][j] = 0;
            }
        }
    }
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("/home/cwolf9/CLionProjects/ccc/in.txt", "r", stdin);
    //freopen("/home/cwolf9/CLionProjects/ccc/out.txt", "w", stdout);
#endif
    int tim = 1;
    while(~scanf("%d%d", &n, &m)) {
        for(int i = 1; i <= n; ++i) mp[i] = - 1;
        for(int i = 1, a, b; i <= m; ++i) {
            a = read(), b = read();
            mp[b] = big(mp[b], a);
        }
        get_dp();
        LL ans = 0;
        for(int i = 0; i <= n; ++i) for(int j = 0; j <= i; ++j) ans = (ans + dp[c][i][j]) % mod;
        printf("%lld\n", (ans + mod) % mod);
    }
#ifndef ONLINE_JUDGE
    cout << "time cost:" << clock() << "ms" << endl;
#endif
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章