CodeForces 154A Hometask dp
题目链接:
http://codeforces.com/problemset/problem/154/A
题意:
给你一个字符串,和若干模板串(长度为2),至少删除多少个字母,使得字符串的字串里面没有模板串。
题解:
dp[i][j]表示合法子串s[0...i]的最后一位为j时的最小花费(花费指删除的字母个数)
对每一位考虑删和不删的情况:
如果删,那么它的最后一位一定为之前出现过的。
如果不删,那么s[i]就是最后一位。
考虑这两种情况的转移就可以了。
时间复杂度:O(n*26*26)
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 1e5 + 10; const int INF = 0x3f3f3f3f; int dp[maxn][33]; int cnt[33]; bool mp[33][33]; char str[maxn]; int len, n; void init() { memset(dp, 0x3f, sizeof(dp)); memset(mp, 0, sizeof(mp)); memset(cnt, -1, sizeof(cnt)); } inline int f(char c) { return c - 'a' + 1; } int main() { while (scanf("%s%d", str, &n) == 2) { init(); len = strlen(str); char s[11]; for (int i = 0; i<n; i++) { scanf("%s", s); mp[f(s[0])][f(s[1])] = mp[f(s[1])][f(s[0])] = 1; } cnt[f(str[0])] = 0; dp[0][f(str[0])] = 0; for (int i = 0; i<len; i++) dp[i][0] = i + 1; for (int i = 1; i<len; i++) { int ch = f(str[i]); cnt[ch] = i; //第i位删 for (int j = 1; j <= 26; j++) { if (cnt[j] != -1) { int k = cnt[j]; dp[i][j] = min(dp[i][j], dp[k][j] + i - k); } } dp[i][ch] = min(dp[i][ch], dp[i - 1][0]); //第i位不删 for (int k = 1; k <= 26; k++) { if (mp[k][ch] == 0) { dp[i][ch] = min(dp[i][ch], dp[i - 1][k]); } } } int ans = INF; for (int i = 1; i <= 26; i++) { ans = min(ans, dp[len - 1][i]); } printf("%d\n", ans); } return 0; }