P4761 [CERC2014]Vocabulary(DP)

題意:
給你三個字符串,這些字符串有些單詞模糊不可認了,用"?“來代表。 現在你可以用任意英文小寫字母來代表它們。要求是使得給定的三個字符串中 所有的”?"被你認定的字母代替後,各不相同且按字典序出現。問有多少種方式。

輸入:先給出一個數字N,代表數據組數。 接下來3*N行,每行給出一個字符串。長度<=1000 000

輸出:輸出結果 Mod 10^9+9

參考自:https://www.cnblogs.com/SGCollin/p/9751265.html
思路:
將這三個字符串一起處理,’?'特殊對待,可視爲任意字符。小於最長長度的部分定義爲0,不會影響相互間大小關係。

字符串間的狀態,可以分爲四種
x=y=zx=y=z
x<y=zx<y=z
x=y<zx=y<z
x<y<zx<y<z

定義g[a][b][i][j][k]g[a][b][i][j][k]代表之前狀態爲a,當前狀態爲b,且當前的三個字符爲i,j,k時候的轉移方案數。

在定義f[i][j]f[i][j]代表處理完前ii個字符,當前狀態爲jj的方案數。
轉移的方式就是 f[i][j]=f[i1][k]g[k][j][s1[i]][s2[i]][s3[i]]f[i][j]=∑f[i-1][k]*g[k][j][s1[i]][s2[i]][s3[i]]

最終要保證狀態爲s1<s2<s3s1<s2<s3,所以結果爲f[len][3]f[len][3]

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <map>

using namespace std;
typedef long long ll;

const int maxn = 1e6 + 10;
const ll mod = 1e9 + 9;
ll f[maxn][4],g[4][4][28][28][28];
int len,len1,len2,len3;
int a1[maxn],a2[maxn],a3[maxn];
char s1[maxn],s2[maxn],s3[maxn];

void Pre() {
    int l1,r1,l2,r2,l3,r3;
    for(int i = 0;i <= 27;i++) {
        for(int j = 0;j <= 27;j++) {
            for(int k = 0;k <= 27;k++) {
                if(i == 27) l1 = 1,r1 = 26;else l1 = r1 = i;
                for(int x = l1;x <= r1;x++) {
                    if(j == 27) l2 = 1,r2 = 26;else l2 = r2 = j;
                    for(int y = l2;y <= r2;y++) {
                        if(k == 27) l3 = 1,r3 = 26;else l3 = r3 = k;
                        for(int z = l3;z <= r3;z++) {
                            if(x == y && y == z) g[0][0][i][j][k]++;
                            if(x < y && y == z) g[0][1][i][j][k]++;
                            if(x == y && y < z) g[0][2][i][j][k]++;
                            if(x < y && y < z) g[0][3][i][j][k]++;
                            
                            if(y < z) g[1][3][i][j][k]++;
                            if(y == z) g[1][1][i][j][k]++;
                            
                            if(x < y) g[2][3][i][j][k]++;
                            if(x == y) g[2][2][i][j][k]++;
                            
                            g[3][3][i][j][k]++;
                        }
                    }
                }
            }
        }
    }
}

void init() {
    scanf("%s%s%s",s1 + 1,s2 + 1,s3 + 1);
    len1 = strlen(s1 + 1);len2 = strlen(s2 + 1);len3 = strlen(s3 + 1);
    len = max(len1,max(len2,len3));
    
    for(int i = 1;i <= len1;i++) a1[i] = s1[i] == '?' ? 27 : s1[i] - 'a' + 1;
    for(int i = 1;i <= len2;i++) a2[i] = s2[i] == '?' ? 27 : s2[i] - 'a' + 1;
    for(int i = 1;i <= len3;i++) a3[i] = s3[i] == '?' ? 27 : s3[i] - 'a' + 1;
    
    for(int i = len1 + 1;i <= len;i++) a1[i] = 0;
    for(int i = len2 + 1;i <= len;i++) a2[i] = 0;
    for(int i = len3 + 1;i <= len;i++) a3[i] = 0;
}

int main() {
    Pre();
    int T;scanf("%d",&T);
    while(T--) {
        init();
        for(int i = 0;i <= len;i++) {
            for(int j = 0;j <= 3;j++) {
                f[i][j] = 0;
            }
        }
        f[0][0] = 1;
        
        for(int i = 1;i <= len;i++) {
            for(int k = 0;k <= 3;k++) {
                if(f[i - 1][k]) {
                    for(int j = 0;j <= 3;j++) {
                        f[i][j] += f[i - 1][k] * g[k][j][a1[i]][a2[i]][a3[i]] % mod;
                        f[i][j] %= mod;
                    }
                }
            }
        }
        
        printf("%lld\n",f[len][3]);
    }
    return 0;
}

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