Codeforces 1163D DP + KMP
阿新 • • 發佈:2019-05-12
獲得 bit 子串 set div ext 出現 思路 light
題意:給你一個字符串s,以及兩個字符串s1,s2.s中有些位置是*,意思是可以隨便填字母,s的子串中如果出現一次s1,就加一分,如果出現一次s2,就減一分。問這個字符串s最多可以得多少分?
思路:
設dp[i][j][k]為到s串的i位置,s1的匹配長度是i,s2的匹配長度是j的情況下可以獲得的最多分數。那麽我們需要枚舉這一位填什麽字符,然後轉移到下一個狀態,所有以我們需要對s1和s2預處理一個東西:對s1/s2串匹配長度為i,並且i +1位置填的是字符c的時候,轉移到的匹配長度,這個需要預處理一下。
代碼:
#include <bits/stdc++.h> #define INF 0x3f3f3f3f using namespace std; const int maxn = 1010; const int maxm = 55; char s[maxn], s1[maxm], s2[maxm]; int kmp_s1[maxm], Next_s1[maxm][26], kmp_s2[maxm], Next_s2[maxm][26]; int dp[maxn][55][55]; void init(char s[maxn], int len, int kmp[maxn], int Next[maxn][26]) { kmp[1] = 0; for (int i = 2, j = 0; i <= len; i++) { while(j && s[j + 1] != s[i])j = kmp[j]; if(s[j + 1] == s[i])j++; kmp[i] = j; } for (int i = 0; i <= len; i++) { for (char c = ‘a‘; c <= ‘z‘; c++) { int now = i; while(now && s[now + 1] != c) now = kmp[now]; if(s[now + 1] == c) now++; Next[i][c - ‘a‘] = now; } } } int main() { scanf("%s%s%s", s + 1, s1 + 1, s2 + 1); int len = strlen(s + 1), n = strlen(s1 + 1), m = strlen(s2 + 1); init(s1, n, kmp_s1, Next_s1); init(s2, m, kmp_s2, Next_s2); memset(dp, 0xcf, sizeof(dp)); dp[0][0][0] = 0; for (int i = 0; i <= len; i++) for (int j = 0; j <= n; j++) for (int k = 0; k <= m; k++) { for (int c = 0; c < 26; c++) { if(s[i + 1] == ‘a‘ + c || s[i + 1] == ‘*‘) { int tmp1 = Next_s1[j][c], tmp2 = Next_s2[k][c]; int tmp = dp[i][j][k] + (tmp1 == n) - (tmp2 == m); dp[i + 1][tmp1][tmp2] = max(dp[i + 1][tmp1][tmp2], tmp); } } } int ans = -INF; for (int i = 0; i <= n; i++) for (int j = 0; j <= m; j++) ans = max(ans, dp[len][i][j]); printf("%d\n", ans); }
Codeforces 1163D DP + KMP