分析
题目要求:
1. 所有的a都在e和i之前,所有的e都在i之前;
2. 所有的o都在u之前。
仔细分析发现如下特点:
* 其实a、e、ia、e、i这三个字符和o、uo、u这两个字符毫无关系,设给定字符串为SS,那么我只要从字符串中选择只包含a、e、ia、e、i且满足规则1的最长子序列,再从字符串SS中选择只包含且满足规则2的最长子序列,再将这两个字符串组合就得到满足规则最长子序列。
具体实现
根据上述分析,发现可以将原问题分成两个小问题来解决。
假设给定字符串"aeieeeeiaa""aeieeeeiaa",如何选择满足所有的a都在e和i之前,所有的e都在i之前的最长子序列呢?最长序列其实就是三段式:"a...ae...ei...i""a...ae...ei...i",aa一定在前面,ee一定在前面。用maxa,maxe,maximaxa,maxe,maxi分别表示字符串SS前个字符组成的子串中能得到的最长以"a,e,i""a,e,i"结尾的最长序列。
那么得到如下转移方程:
同样的方式,可以得到由oo和组成的满足“所有的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;
}
如有不当之处欢迎指出!