• Bzoj 2664 [BeiJing wc2012]孵化者


    gate

    和我签订契约,成为马猴烧酒吧!

    这题还挺有趣的...

    区间dp(没想到吧)

    设当前的Witch串为s

    f[x][i][j]代表字符x是否能克制s中的区间(i,j)

    在dp的过程中,因为x只有'A'-'Z'26种,所以这里就直接暴力枚举。

    而x的克制或孵化规则,一共也只有20种,所以也直接枚举。

    首先初始化:

    克制关系都是1v1的,所以首先要把哪个字符能克制s[i]处理出来。

    也就是说,对于x='A'-'Z',检查x是否能克制s[i]。

    至于x能不能在Spell中出现...先不用考虑。

    枚举i、x、x的克制关系,若有x->s[i],则f[x][i][i] = true

    for(int i = 0; i < n; i++)
        for(int x = 0; x < 26; x++)
            for(int t = 0; t < atk[x].size(); t++)
                if(atk[x][t] == s[i])
                    f[x][i][i] = 1;
    // atk[x][t]=y 则x的第t个克制关系为 x->y
    关键代码(和前面写的不太一样)

    最开始只有一个S,所以想消灭整个Witch,必须要孵化新的。

    一张卡只能孵化成两张,所以枚举断点k

    设a,b代表字符x的某个孵化关系所孵化出的第1,2张卡的字符

    (i,k)由a克制,(k+1,j)由b克制,

    状态转移方程:f[x][i][j] = f[a][i][k] && f[b][k+1][j]

    for(int len = 2; len <= n; len++)
        for(int i = 0; i+len-1 < n; i++) {
            int j = i+len-1;
            for(int x = 0; x < 26; x++)
                for(int t = 0; t < spl[1][x].size(); t++)
                    for(int k = i; k <= j; k++)
                        if(f[spl[1][x][t]-'A'][i][k] && f[spl[2][x][t]-'A'][k+1][j])
                            f[x][i][j] = 1;
        }
    // spl[1][x][t]=y,spl[2][x][t]=z 则x的第t个孵化关系为x->yz
    关键代码(和前面写的不太一样)

    最后检查f['S'][1][len]是否为true就可以了!

    完整代码如下

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #define MogeKo qwq
    #include<vector>
    using namespace std;
    
    int n,m;
    int f[30][25][25];
    char s[25];
    vector <char> atk[30],spl[3][30];
    
    int main() {
        scanf("%d%d",&n,&m);
        for(int i = 1; i <= n; i++) {
            scanf("%s",s);
            atk[s[0]-'A'].push_back(s[3]);
        }
        for(int i = 1; i <= m; i++) {
            scanf("%s",s);
            spl[1][s[0]-'A'].push_back(s[3]);
            spl[2][s[0]-'A'].push_back(s[4]);
        }
        while(~scanf("%s",s)) {
            n = strlen(s);
            memset(f,0,sizeof(f));
            for(int i = 0; i < n; i++)
                for(int x = 0; x < 26; x++)
                    for(int t = 0; t < atk[x].size(); t++)
                        if(atk[x][t] == s[i])
                            f[x][i][i] = 1;
    
            for(int len = 2; len <= n; len++)
                for(int i = 0; i+len-1 < n; i++) {
                    int j = i+len-1;
                    for(int x = 0; x < 26; x++)
                        for(int t = 0; t < spl[1][x].size(); t++)
                            for(int k = i; k <= j; k++)
                                if(f[spl[1][x][t]-'A'][i][k] && f[spl[2][x][t]-'A'][k+1][j])
                                    f[x][i][j] = 1;
                }
            if(f['S'-'A'][0][n-1]) printf("YES
    ");
            else printf("NO
    ");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    888. Uncommon Words from Two Sentences
    344. Reverse String
    151. Reverse Words in a String
    557. Reverse Words in a String III
    811. Subdomain Visit Count
    上海市公积金、养老保险、医疗保险转出事宜
    476. Number Complement
    方法重载的条件
    简单工厂模式
    单例模式
  • 原文地址:https://www.cnblogs.com/mogeko/p/11821916.html
Copyright © 2020-2023  润新知