Light OJ 1051

题目大意: 给你一个字符串,字符串由大写字母和‘?’组成,大写字母可以变成任意一个字母。现在我们定义字符串, 如果有超过三个连续的元音字母或者连续五个辅音字母,那么我们称这个字符串是“BAD”,否则称这个字符串是“GOOD”, 如果字符串既可以是“GOOD”又可以是 “BAD” 那么我们称这个字符串是“MIXED”.

题目分析:
刚开始做的时候确实没做出来,后来看了题解,确实是有点脑洞的,之前一直想不出怎么去DP。
dp[字符串的第i个位置][以第i个位置为终点连续最长的元音为i是否存在][连续最长为j是否存在] = 这个状态是否存在。
在这个DP过程中,一旦第i个位置出现了长度为3的元音或者长度为5的辅音的时候,我们后面的DP式子就不会再出现存在的情况了。
 
 
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;
const int INF = 1e9+7;
const int MAXN = 555;
bool dp[MAXN][10][10];///dp[位置][元音][辅音]
char str[MAXN];
bool OK(char ch)
{
    return ch == 'A' || ch == 'E' || ch == 'O' || ch == 'I' || ch == 'U';
}

void solve(int n)
{
    memset(dp, false, sizeof(dp));
    dp[0][0][0] = true;

    for(int i=1; i<=n; i++)
    {
        for(int j=0; j<=4; j++)
        {
            if(str[i] == '?' || !OK(str[i]))///辅音
                dp[i][0][j+1] |= dp[i-1][0][j];
            if(str[i] == '?' ||  OK(str[i]))
                dp[i][1][0] |= dp[i-1][0][j];
        }
        for(int j=0; j<=2; j++)
        {
            if(str[i] == '?' || OK(str[i]))
                dp[i][j+1][0] |= dp[i-1][j][0];
            if(str[i] == '?' || !OK(str[i]))
                dp[i][0][1] |= dp[i-1][j][0];
        }
    }
    int good = 0, bad = 0;
    for(int i=0; i<=4; i++)
    if(dp[n][0][i]) good = 1;

    for(int i=0; i<=2; i++)
    if(dp[n][i][0]) good = 1;

    for(int i=1; i<=n; i++)
    if(dp[i][0][5] || dp[i][3][0]) bad = 1;

    if(good && bad) puts("MIXED");
    else if(good) puts("GOOD");
    else puts("BAD");
}


int main()
{
    int T, cas = 1;
    scanf("%d", &T);
    while(T --)
    {
        scanf("%s", str + 1);
        printf("Case %d: ", cas ++);
        solve(strlen(str+1));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/chenchengxun/p/4919353.html