bzoj5147bzoj2121loj6701 字符串游戏
做不出來雜題,到處找題做
看到$loj$上新出了一道題,覺得很神仙不錯,
還記得Censoring嗎(一個AC自動機(jī)的題)
這個題求最優(yōu)解,數(shù)據(jù)范圍$150$
題解
數(shù)據(jù)范圍非常小,首先貪心肯定不行,考慮AC自動機(jī)上$dp$?
好吧其實是區(qū)間$dp$
一個直接的想法是維護(hù)$f[l][r]=0/1$表示是否可以清空$l$,$r$這一段子段
然而轉(zhuǎn)移起來很難轉(zhuǎn)移,考慮再定義一個數(shù)組$g[l][r][i][w]=0/1$表示是否可以清成第$i$個模式串的前$w$位
考慮$g$轉(zhuǎn)移,
1.直接匹配$g[l][r][i][w]|=g[l][r-1][i][w-1]$其中主串$str[r]==c[i][w]$表示若$l,r-1$可以清成第$i$個模式串前$w-1$位那么若當(dāng)前兩個可以匹配上必然$l,r$可以清成第$i$個模式串前$w$位
2.由幾部分拼湊$g[l][r][i][w]|=g[l][q-1][i][w]\&f[q][r]$表示$q-r$被清空那么$g$顯然可以轉(zhuǎn)移
那么根據(jù)$f$定義$f[l][r]|=g[l][r][i][len[i]]$
舉個例子$momooo$ 模式串$moo$
先$g[3][5][1][3]=1$,得$f[3][5]=1$得$g[1][5][1][2]=1$(由$f[3][5]$)轉(zhuǎn)移 再進(jìn)行一步匹配$f[3][6][1][3]=1$得$f[1][6]=1$可以全部清空
那么$ans$根據(jù)類似最長上升子序列求
$ans[i]=min(ans[i-1]+1,ans[l-1](f[l][i]==1))$兩層循環(huán)枚舉
考慮炸內(nèi)存?
狀壓,怎么狀壓,壓掉一維,這里不再解釋,因為數(shù)據(jù)點(diǎn)足夠水,這已經(jīng)足以通過測試點(diǎn)
代碼
#include<bits/stdc++.h> using namespace std; #define A 152 #define ll long long ll len[A],ans[A]; bool f[A][A],g[A][A][52][52]; ll n,cnt; char c[A][A],str[A]; int main(){scanf("%s",str+1);n=strlen(str+1);scanf("%lld",&cnt);for(ll i=1;i<=cnt;i++){scanf("%s",c[i]+1);len[i]=strlen(c[i]+1);}for(ll i=1;i<=n;i++){f[i][i-1]=1;for(ll j=1;j<=cnt;j++){g[i][i-1][j][0]=1;}}for(ll k=1;k<=n;k++){//枚舉當(dāng)前長度for(ll l=1;l<=n-k+1;l++){ll r=l+k-1;for(ll w=1;w<=cnt;w++){for(ll now=1;now<=len[w];now++){if(c[w][now]==str[r])g[l][r][w][now]|=g[l][r-1][w][now-1];}for(ll now=1;now<=len[w];now++){for(ll i=l;i<=r;i++){g[l][r][w][now]|=g[l][i-1][w][now]&f[i][r];}}}for(ll w=1;w<=cnt;w++)f[l][r]|=g[l][r][w][len[w]];}}for(ll i=1;i<=n;i++){ans[i]=ans[i-1]+1;for(ll j=1;j<=i;j++){if(f[j][i]){ans[i]=min(ans[i],ans[j-1]);}}}printf("%lld\n",ans[n]); } View Code?
轉(zhuǎn)載于:https://www.cnblogs.com/znsbc-13/p/11579220.html
總結(jié)
以上是生活随笔為你收集整理的bzoj5147bzoj2121loj6701 字符串游戏的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 再生资源简易征收是否需要备案?
- 下一篇: NOIP模拟测试49·50「养花·折射·