題目描述spa
輸入code
輸出blog
輸出一個整數,表示L的最短長度。字符串
樣例輸入string
aaabccd
3
ac
abc
aaa
it
樣例輸出io
2class
題解im
咱們考慮:每次刪除連續的一段,對應到原串上即:刪除 $[l,r]$ 中全部未被刪除的字符。其中 $l,r$ 都未被刪除。img
這樣就至關於選擇若干區間來刪除。
注意到選擇的任意兩個區間要麼包含要麼不相交(相離),對於相鄰的相離的也能夠看做是包含(右區間左端點看做是左區間左端點,即一個空位置),所以只有包含關係。
那麼以下圖:
先選擇 $[b,c]$ 的串 $S$ ,再選擇 $[a,d]$ 的串 $T$ ,能夠看做是處理出 $[a,b)$ 可以匹配到 $T$ 的中間位置,$[b,c]$ 可以匹配到 $S$ 的結束位置(即刪除掉),進而推知 $[a,c]$ 可以匹配到 $T$ 的中間位置,再向右匹配得知 $[a,d]$ 可以匹配到 $T$ 的結束位置。
考慮區間dp。設 $f[l][r]$ 表示 $[l,r]$ 是否能夠所有刪掉,再設 $g[l][r][i][j]$ 表示 $[l,r]$ 是否可以刪成第 $i$ 個字符串的前 $j$ 個字符。
那麼考慮區間 $[l,r]$ ,若是進行匹配的話轉移爲 $g[l][r][i][j]=g[l][r-1][i][j-1]$ ,前提條件 $str[r]==w[i][j]$ ,即區間右端點和第 $i$ 個串的第 $j$ 個字符相同。
若是不進行匹配的話,$r$ 必定在某個 $[k,r]$ 中被消掉,所以枚舉 $k\in[l,r]$ ,轉移爲 $g[l][r][i][j]=g[l][k-1][i][j]\&\&f[k][r]$ 。
根據 $f$ 的定義有轉移 $f[l][r]=g[l][r][i][len[i]]$ 。
這樣咱們就可以推出 $f$ 和 $g$ 。
再考慮答案:設 $h[i]$ 表示前 $i$ 個字符的答案,那麼 $h[i]=h[i-1]+1$ ;若是某個 $j$ 知足 $f[j][i]=1$ ,即 $[j,i]$ 能刪掉,則還有 $h[i]=h[j-1]$ 。
最終答案就是 $h[n]$ 。
時間複雜度 $O(n^3·m·len)$
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; bool f[155][155] , g[155][155][35][25]; char str[155] , w[35][25]; int c[35] , ans[155]; int main() { int n , m , len , l , r , i , j , k; scanf("%s%d" , str + 1 , &m) , n = strlen(str + 1); for(i = 1 ; i <= m ; i ++ ) scanf("%s" , w[i] + 1) , c[i] = strlen(w[i] + 1); for(i = 1 ; i <= n ; i ++ ) { f[i][i - 1] = 1; for(j = 1 ; j <= m ; j ++ ) g[i][i - 1][j][0] = 1; } for(len = 1 ; len <= n ; len ++ ) { for(l = 1 ; l <= n - len + 1 ; l ++ ) { r = l + len - 1; for(i = 1 ; i <= m ; i ++ ) { for(j = 1 ; j <= c[i] ; j ++ ) if(str[r] == w[i][j]) g[l][r][i][j] |= g[l][r - 1][i][j - 1]; for(j = 0 ; j <= c[i] ; j ++ ) for(k = l ; k <= r ; k ++ ) g[l][r][i][j] |= g[l][k - 1][i][j] & f[k][r]; } for(i = 1 ; i <= m ; i ++ ) f[l][r] |= g[l][r][i][c[i]]; } } for(i = 1 ; i <= n ; i ++ ) { ans[i] = ans[i - 1] + 1; for(j = 1 ; j <= i ; j ++ ) if(f[j][i]) ans[i] = min(ans[i] , ans[j - 1]); } printf("%d\n" , ans[n]); return 0; }