Hihocoder1690 AEIOU (动态规划)

分析

题目要求:
1. 所有的a都在e和i之前,所有的e都在i之前;
2. 所有的o都在u之前。

仔细分析发现如下特点:
* 其实 aei a 、 e 、 i 这三个字符和 ou o 、 u 这两个字符毫无关系,设给定字符串为 S S ,那么我只要从字符串S中选择只包含 aei a 、 e 、 i 且满足规则1的最长子序列,再从字符串 S S 中选择只包含ou且满足规则2的最长子序列,再将这两个字符串组合就得到满足规则最长子序列。

具体实现

根据上述分析,发现可以将原问题分成两个小问题来解决。

假设给定字符串 "aeieeeeiaa" " a e i e e e e i a a " ,如何选择满足所有的a都在e和i之前,所有的e都在i之前的最长子序列呢?最长序列其实就是三段式: "a...ae...ei...i" " a . . . a e . . . e i . . . i " a a 一定在e前面, e e 一定在i前面。用 maxa,maxe,maxi m a x a , m a x e , m a x i 分别表示字符串 S S i个字符组成的子串中能得到的最长以 "a,e,i" " a , e , i " 结尾的最长序列。

那么得到如下转移方程:

maxa=maxa+1 m a x a = m a x a + 1 ,因为a的前面只能是a

maxe=max{maxa,maxe}+1 m a x e = m a x { m a x a , m a x e } + 1 ,因为e的前面可以是a或者e

maxi=max{maxa,maxe,maxi}+1 m a x i = m a x { m a x a , m a x e , m a x i } + 1 ,因为i的前面可以是a、e或者i

同样的方式,可以得到由 o o u组成的满足“所有的o都在u之前”的最长子序列。

AC代码

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxn = 1000000 + 5;

char s[maxn];
int dp[5];  // a e i o u

int main() {
    while(scanf("%s", s) != EOF) {
        memset(dp, 0, sizeof(dp));
        int n = strlen(s);
        for(int i = 0; i < n; i++) {
            if(s[i] == 'a') {
                //the previous charactor must be 'a'
                dp[0] = dp[0] + 1;
            } else if(s[i] == 'e') {
                //the previous charactor must be 'a' or 'e'
                dp[1] = max(dp[0] + 1, dp[1] + 1);
            } else if(s[i] == 'i') {
                //the previous charactor must be 'a' or 'e' or 'i'
                int tmp = max(dp[0] + 1, dp[1] + 1);
                dp[2] = max(tmp, dp[2] + 1);
            } else if(s[i] == 'o') {
                //the previous charactor must be 'o'
                dp[3] = dp[3] + 1;
            } else {
                //the previous charactor must be 'o' or 'u'
                dp[4] = max(dp[3] + 1, dp[4] + 1);
            }
        }
        int max1 = max(dp[0], dp[1]);
        max1 = max(dp[2], max1);
        int max2 = max(dp[3], dp[4]);
        printf("%d\n", max1 + max2);
    }
    return 0;
}

如有不当之处欢迎指出!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值