bzoj千题计划234:bzoj3802: Vocabulary

http://www.lydsy.com/JudgeOnline/problem.php?id=3802

 

dp[i][0/1/2/3]  表示前i个字母,第1、2个字符串,第2、3个字符串的关系分别为 < < , = < , < = , = =

枚举前i-1个字母 构成的关系

再枚举3个字符串的字母 转移

时间复杂度为 O(N* 26^3)

 

优化转移:

转移都是dp[i-1][0/1/2/3]-->dp[i][0/1/2/3]

预处理出f[i][j][k][s:0~3][t:0~3] 表示前面字母构成的字符串的关系为s,3个字符串分别加上1个字母i、j、k后转移到关系t的方案数

转移的时候不枚举3个字符串的字母,枚举新的关系0~3 

直接用f数组转移

 

#include<cstdio>
#include<cstring>

using namespace std;

#define N 1000002

const int mod=1e9+9;

char s1[N],s2[N],s3[N]; 

int f[28][28][28][4][4];
int dp[N][4];
//0:i<j<k  1:i=j<k  2:i<j=k  3:i=j=k  

void pre()
{
    int li,ri,lj,rj,lk,rk;
    int t;
    for(int i=0;i<=27;++i)
        for(int j=0;j<=27;++j)
            for(int k=0;k<=27;++k)
            {
                if(i==27) li=1,ri=26;
                else li=ri=i;
                if(j==27) lj=1,rj=26;
                else lj=rj=j;
                if(k==27) lk=1,rk=26;
                else lk=rk=k;
                for(int ci=li;ci<=ri;++ci)
                    for(int cj=lj;cj<=rj;++cj)
                        for(int ck=lk;ck<=rk;++ck) 
                            for(int s=0;s<=3;++s)
                            {
                                if(!s) t=0;
                                else if(s==1)
                                {
                                    if(ci==cj) t=1;
                                    else if(ci<cj) t=0;
                                    else t=-1;
                                }
                                else if(s==2)
                                {
                                    if(cj==ck) t=2;
                                    else if(cj<ck) t=0;
                                    else t=-1;
                                }
                                else
                                {
                                    if(ci>cj || ci>ck || cj>ck) t=-1;
                                    else if(ci<cj && cj<ck) t=0;
                                    else if(ci==cj && cj<ck) t=1;
                                    else if(ci<cj && cj==ck) t=2;
                                    else t=3;
                                }
                                if(t>=0) f[i][j][k][s][t]++;
                            }
            }    
} 

int main()
{
    pre();
    int T;
    scanf("%d",&T);
    int l1,l2,l3,len;
    int x,y,z;
    while(T--)
    {
        scanf("%s",s1+1);
        scanf("%s",s2+1);
        scanf("%s",s3+1);
        l1=strlen(s1+1); 
        len=l1;
        l2=strlen(s2+1);
        if(l2>len) len=l2;
        l3=strlen(s3+1);
        if(l3>len) len=l3;
        while(l1!=len) s1[++l1]='a'-1;
        while(l2!=len) s2[++l2]='a'-1;
        while(l3!=len) s3[++l3]='a'-1;
        for(int i=1;i<=len;++i)
            for(int j=0;j<=3;++j)
                dp[i][j]=0;
        dp[0][3]=1;
        for(int i=1;i<=len;++i)
        {
            x=s1[i]-'a'+1;
            if(x<0) x=27;
            y=s2[i]-'a'+1;
            if(y<0) y=27;
            z=s3[i]-'a'+1;
            if(z<0) z=27;
            for(int j=0;j<=3;++j)
                if(dp[i-1][j])
                    for(int k=0;k<=3;++k)
                        dp[i][k]=(dp[i][k]+(long long)dp[i-1][j]*f[x][y][z][j][k]%mod)%mod;
        }
        printf("%d\n",dp[len][0]);
    }
} 

 

3802: Vocabulary

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 185  Solved: 68
[Submit][Status][Discuss]

Description

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

 

Input

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

 

Output

输出结果 Mod 10^9+9

 

Sample Input

3
?heoret?cal
c?mputer
?cience
jagiellonia
?niversity
kra?ow
?
b
c

Sample Output

42562
52
1
posted @ 2018-02-12 20:45  TRTTG  阅读(284)  评论(0编辑  收藏  举报