P4761 [CERC2014]Vocabulary(DP)

题意:
给你三个字符串,这些字符串有些单词模糊不可认了,用"?“来代表。 现在你可以用任意英文小写字母来代表它们。要求是使得给定的三个字符串中 所有的”?"被你认定的字母代替后,各不相同且按字典序出现。问有多少种方式。

输入:先给出一个数字N,代表数据组数。 接下来3*N行,每行给出一个字符串。长度<=1000 000

输出:输出结果 Mod 10^9+9

参考自:https://www.cnblogs.com/SGCollin/p/9751265.html
思路:
将这三个字符串一起处理,’?'特殊对待,可视为任意字符。小于最长长度的部分定义为0,不会影响相互间大小关系。

字符串间的状态,可以分为四种
x = y = z x=y=z
x < y = z x<y=z
x = y < z x=y<z
x < y < z x<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] 代表处理完前 i i 个字符,当前状态为 j j 的方案数。
转移的方式就是 f [ i ] [ j ] = f [ i 1 ] [ k ] g [ k ] [ j ] [ s 1 [ i ] ] [ s 2 [ i ] ] [ s 3 [ i ] ] f[i][j]=∑f[i-1][k]*g[k][j][s1[i]][s2[i]][s3[i]]

最终要保证状态为 s 1 < s 2 < s 3 s1<s2<s3 ,所以结果为 f [ l e n ] [ 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;
}

原创文章 930 获赞 38 访问量 5万+

猜你喜欢

转载自blog.csdn.net/tomjobs/article/details/106075205