題目描述
給你乙個字串l和乙個字串集合s,如果s的某個子串在s集合中,那麼可以將其刪去,剩餘的部分拼到一起成為新的l串。問:最後剩下的串長度的最小值。
輸入輸入的第一行包含乙個字串,表示l。
第二行包含乙個數字n,表示集合s中元素個數。
以下n行,每行乙個字串,表示s中的乙個元素。
輸入字串都只包含小寫字母。
輸出輸出乙個整數,表示l的最短長度。
樣例輸入
aaabccd3ac
abcaaa
樣例輸出2題解
我們考慮:每次刪除連續的一段,對應到原串上即:刪除 $[l,r]$ 中所有未被刪除的字元。其中 $l,r$ 都未被刪除。
這樣就相當於選擇若干區間來刪除。
注意到選擇的任意兩個區間要麼包含要麼不相交(相離),對於相鄰的相離的也可以看作是包含(右區間左端點看作是左區間左端點,即乙個空位置),因此只有包含關係。
那麼如下圖:
先選擇 $[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 #include #include 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()
for(len = 1 ; len <= n ; len ++ )
for(i = 1 ; i <= m ; i ++ ) f[l][r] |= g[l][r][i][c[i]];
} }for(i = 1 ; i <= n ; i ++ )
printf("%d\n" , ans[n]);
return 0;
}
bzoj 2121 字串遊戲
題目大意 給你乙個大字串和乙個字串的集合,每次可以從字串的集合中選出乙個,如果那個大字串中包含了這個字串,就可以從大串中將小串刪掉,刪完後兩邊接起來,求刪完後大串最少剩幾個字元 大串 150,小串 20,小串個數 30 這題沒想著怎麼做,主要還是太弱了。首先可以設f i j k l 代表第i個到第j...
bzoj 2121 字串遊戲
bx正在進行乙個字串遊戲,他手上有乙個字串l,以及其他一些字串的集合s,然後他可以進行以下操作 對於乙個在集合s中的字串p,如果p在l中出現,bx就可以選擇是否將其刪除,如果刪除,則將刪除後l 成的左右兩部分合併。舉個例子,l abcdefg s 如果bx選擇將 de 從l中刪去,則刪後的l abc...
BZOJ2121 字串遊戲
區間dp 用c l r 表示l r是否能被全部刪掉,f l r k x 表示l r和第k個串匹配是否能匹配到第x位,注意到小串的長度 21,而且f是個bool變數,所以可以把x壓成int,而推一下f的轉移方程發現對於不同的l,他們之間是互不影響的,所以可以把l這一維刪掉 那麼列舉左端點,f r k ...