• bzoj3802 Vocabulary


    3802: Vocabulary

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 193  Solved: 70
    [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
    分析:一道特别好的题目!
       这种计数题一看就知道要用dp做,但是状态怎么定义呢?首先肯定要有一维i表示到了第i个字符. 仅仅只有这一维不能转移,字符串的长度有100w,那么另一维肯定特别小,猜测一下,应该是表示的某种状态.
       如果将3个字符串的状态用数字表示. 0表示s1 < s2 < s3,1表示s1 < s2 = s3,2表示s1 = s2 < s3,3表示s1 = s2 = s3.最后要求的状态就是0.这4种状态是可以互相转化的,而且关键因素在于最后一个字符.那么可以令f[i][j]表示3个字符串的前i个字符中,状态为j的方案数,每次转移就枚举3个字符串i位置上的字符,转移到i+1.总复杂度O(n*26^3).
       这样显然会超时.考虑如何优化它. 算法的瓶颈在于每次转移都必须要枚举3个位置上的字符. 前面说过,4种状态的转化关键因素在于最后一个字符.那么我们可以预处理出一个数组g[i][j][k][s][t]表示3个字符串分别往后加字符i,j,k,从状态s转移到状态t的方案数.这个预处理就很简单了,枚举i,j,k,s,t,分类讨论一下就可以了.
       最后的转移方程式就是f[i][k] = f[i - 1][j] * g[x][y][z][j][k]. x,y,z分别对应3个字符串第i位的字符.
       重要的思想,预处理. 如果dp转移出现大量的重复枚举并且这些枚举得到的值都是可以预先算出来的话,就先算出来存到数组里.
       我认为这道题和bzoj1009比较像,它们完全不是一类题,为什么我会这么想呢?bzoj1009的解法中,我知道f(i)可以转移到f(i+1)的哪些状态去,但并不能很容易地知道f(i)由f(i-1)的哪些状态转移来,于是就开了一个数组,存储f(i - 1)的某个状态到f(i)的某个状态的方案数.枚举各种情况乘一下就好了.
       这道题也可以这么理解.也是比较难知道f[i][j]由f[i-1]的哪些状态推来,没关系,维护一个数组保存方案数就好了嘛.
       坑点:直接memset f数组会T掉,需要手动清空,也就是数组很大,但是串长远远不到.
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long ll;
    const int mod = 1e9+9,maxn = 1000010;
    int T,len1,len2,len3,len;
    char s1[maxn],s2[maxn],s3[maxn];
    int a1[maxn],a2[maxn],a3[maxn];
    ll f[maxn][5],g[30][30][30][5][5];
    
    void init()
    {
        for (int i = 0; i <= 27; i++)
            for (int j = 0; j <= 27; j++)
                for (int k = 0; k <= 27; k++)
                {
                    int l1,l2,l3,r1,r2,r3;
                    if (i == 27)
                        l1 = 1,r1 = 26;
                    else
                        l1 = r1 = i;
                    if (j == 27)
                        l2 = 1,r2 = 26;
                    else
                        l2 = r2 = j;
                    if (k == 27)
                        l3 = 1,r3 = 26;
                    else
                        l3 = r3 = k;
                    for (int x = l1; x <= r1; x++)
                        for (int y = l2; y <= r2; y++)
                            for (int z = l3; z <= r3; z++)
                                for (int s = 0; s <= 3; s++)
                                {
                                    int t = -1;
                                    if (s == 0)
                                        t = 0;
                                    else if (s == 1)
                                    {
                                        if (y == z)
                                            t = 1;
                                        else if (y < z)
                                            t = 0;
                                        else
                                            t = -1;
                                    }
                                    else if (s == 2)
                                    {
                                        if (x == y)
                                            t = 2;
                                        else if (x < y)
                                            t = 0;
                                        else
                                            t = -1;
                                    }
                                    else
                                    {
                                        if (x == y && y == z)
                                            t = 3;
                                        else if (x == y && y < z)
                                            t = 2;
                                        else if(x < y && y == z)
                                            t = 1;
                                        else if (x < y && y < z)
                                            t = 0;
                                        else if (x > y || y > z || x > z)
                                            t = -1;
                                    }
                                    if (t != -1)
                                        g[i][j][k][s][t]++;
                                }
                }
    }
    
    int main()
    {
        init();
        scanf("%d",&T);
        while (T--)
        {
            scanf("%s",s1 + 1);
            len1 = strlen(s1 + 1);
            scanf("%s",s2 + 1);
            len2 = strlen(s2 + 1);
            scanf("%s",s3 + 1);
            len3 = strlen(s3 + 1);
            for (int i = 1; i <= len1; i++)
                a1[i] = s1[i] - 'a' + 1;
            for (int i = 1; i <= len2; i++)
                a2[i] = s2[i] - 'a' + 1;
            for (int i = 1; i <= len3; i++)
                a3[i] = 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;
            len = max(len1,max(len2,len3));
            for (int i = 1; i <= len; i++)
                for (int j = 0; j <= 3; j++)
                    f[i][j] = 0;
            f[0][3] = 1;
            for (int i = 1; i <= len; i++)
            {
                int x = a1[i],y = a2[i],z = a3[i];
                if (x < 0)
                    x = 27;
                if (y < 0)
                    y = 27;
                if (z < 0)
                    z = 27;
                for (int j = 0; j <= 3; j++)
                {
                    if (f[i - 1][j])
                    {
                        for (int k = 0; k <= 3; k++)
                        {
                            f[i][k] = (f[i][k] + f[i - 1][j] * g[x][y][z][j][k] % mod) % mod;
                        }
                    }
                }
            }
            printf("%lld
    ",f[len][0] % mod);
        }
    
        return 0;
    }
  • 相关阅读:
    我的WCF之旅(1):创建一个简单的WCF程序
    网页设计中颜色的搭配
    CSS HACK:全面兼容IE6/IE7/IE8/FF的CSS HACK
    UVa 1326 Jurassic Remains
    UVa 10340 All in All
    UVa 673 Parentheses Balance
    UVa 442 Matrix Chain Multiplication
    UVa 10970 Big Chocolate
    UVa 679 Dropping Balls
    UVa 133 The Dole Queue
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8486410.html
Copyright © 2020-2023  润新知