分析
题目要求:
1. 所有的a都在e和i之前,所有的e都在i之前;
2. 所有的o都在u之前。
仔细分析发现如下特点:
* 其实
a、e、i
a
、
e
、
i
这三个字符和
o、u
o
、
u
这两个字符毫无关系,设给定字符串为
S
S
,那么我只要从字符串中选择只包含
a、e、i
a
、
e
、
i
且满足规则1的最长子序列,再从字符串
S
S
中选择只包含且满足规则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 一定在前面。用 maxa,maxe,maxi m a x a , m a x e , m a x i 分别表示字符串 S S 前个字符组成的子串中能得到的最长以 "a,e,i" " a , e , i " 结尾的最长序列。
那么得到如下转移方程:
同样的方式,可以得到由 o o 和组成的满足“所有的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;
}
如有不当之处欢迎指出!