HDU6578——blank 動態規劃

題目來源 HDU 6578

題意

總共有nn個編號,每個編號可以填充一個數字,分別爲{0,1,2,3}\{0,1,2,3\}。有mm個條件,每個條件組成爲l,r,xl,r,x表示在區間[l,r][l,r]內的不同數字的個數爲xx個。
問總共有多少種填充的方式,結果對998244353取模。

題解

定義dp[x][y][z][i]dp[x][y][z][i]表示從前向後,當填充到第ii個格子的時候,4個數字最後出現的位置分別爲x,y,z,ix,y,z,i時的方案數。其中xyzix\le y \le z\le i。最初始的狀態,在x,y,z,ix,y,z,i爲0時取等號,表示目前所有的數字都沒有出現。
數字的種類是不重要的,因爲計算的過程已經把不同的數字組合方式計算進去了。重要的在填充第ii個格子的時候從第i1i-1的方案轉移過來。

填充當前格子的時候,我們有四種數字的一個
如果我們填充的數字和xx位置的數字是一樣的,那麼轉移狀態爲
dp[x][y][z][i1]dp[y][z][i1][i]dp[x][y][z][i-1] \rightarrow dp[y][z][i-1][i]
所以dp轉移方式爲
dp[y][z][i1][i]+=dp[x][y][z][i1] dp[y][z][i-1][i] +=dp[x][y][z][i-1]

同樣的方式,如果取的數字和yy位置的數字是一樣的。那麼
dp[x][z][i1][i]+=dp[x][y][z][i1]dp[x][z][i-1][i] += dp[x][y][z][i-1]
類比如下
dp[x][y][i1][i]+=dp[x][y][z][i1]dp[x][y][i-1][i] += dp[x][y][z][i-1]
dp[x][y][z][i]+=dp[x][y][z][i1]dp[x][y][z][i] += dp[x][y][z][i-1]

然後對於每一個以ii爲右端點的區間,枚舉狀態檢查是否滿足條件。即每個編號的最後一次出現的時候是否在區間內,然後判斷要求區間內的編號數和要求的編號數是否相同。

由於第4維是原始空間,則會爆掉規定內存,所以需要用滾動數組來優化內存。

#include <iostream>
#include <algorithm>
#include <vector>
#include <cstdio>
#include <cstring>
using namespace std;

const int mod = 998244353;
int T;
int n,m;
long long dp[110][110][110][2];

struct Position {
    int L;
    int num ;
};

vector<Position> p[110];
int main()
{
    scanf("%d", &T);
    while(T--) {
        scanf("%d %d", &n, &m);
        for(int i = 0;i<110;i++) p[i].clear();
        for(int i = 0,l, r, x ;i< m;i++) {
            scanf("%d %d %d", &l, &r, &x);
            p[r].push_back({l, x});
        }
        dp[0][0][0][0] = 1;
        int cur = 1,pre = 0;
        for(int  i = 1;i<=n;i++) {
            for(int z = 0;z<=i;z++) {
                for(int y = 0;y<=z;y++) {
                    for(int x = 0;x<=y;x++) {
                        dp[x][y][z][cur] = 0;
                    }
                }
            }
            for(int z = 0;z<i;z++) {
                for(int y = 0;y<=z;y++) {
                    for(int x = 0; x<=y;x++) {
                        long long temp = dp[x][y][z][pre];
                        dp[x][y][z][cur] += temp ;
                        dp[y][z][i-1][cur] += temp;
                        dp[x][z][i-1][cur] += temp;
                        dp[x][y][i-1][cur] += temp;

                        dp[x][y][z][cur] %= mod ;
                        dp[y][z][i-1][cur] %= mod;
                        dp[x][z][i-1][cur] %= mod;
                        dp[x][y][i-1][cur] %= mod;

                    }
                }
            }
            for(unsigned int  pp = 0;pp < p[i].size(); pp++) {
                for( int z = 0;z< i;z++) {
                    for(int y = 0;y<=z;y++) {
                        for(int x = 0;x<=y;x++) {
                            int temp = 1 + (z >= p[i][pp].L ? 1:0)
                                         + (y >= p[i][pp].L ? 1:0)
                                         + (x >= p[i][pp].L ? 1:0);
                            if(temp != p[i][pp].num) {
                                dp[x][y][z][cur] = 0;
                            }
                        }
                    }
                }
            }
            swap(pre, cur);
        }
        long long ans  = 0;
        for (int z = 0;z<n;z++) {
            for(int y = 0;y<=z;y++) {
                for(int x = 0;x<=y;x++){
                    ans += dp[x][y][z][pre];
                    ans %= mod;
                }
            }
        }
        printf("%lld\n", ans);

    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章