CodeForces - 1550E Stringforces(二分+状压dp)
題目鏈接:點(diǎn)擊查看
題目大意:給出一個(gè)長(zhǎng)度為 nnn 的字符串,只包含前 kkk 個(gè)小寫(xiě)字母以及通配符 ???,現(xiàn)在可以將通配符替換成任意的前 kkk 個(gè)字母中的一個(gè)。設(shè) f[i]f[i]f[i] 為第 iii 個(gè)字母在字符串中,最長(zhǎng)的連續(xù)子段的長(zhǎng)度,現(xiàn)在要求所有 f[i]f[i]f[i] 中最小值的最大值
題目分析:讀完題一下子根據(jù)復(fù)雜度把正解分析出來(lái)了,可是怎么也沒(méi)辦法往 dpdpdp 上去靠。因?yàn)?k≤17k\le 17k≤17,又因?yàn)?217≈2e52^{17}≈2e5217≈2e5,所以不難想到二分+狀壓dp,時(shí)間復(fù)雜度剛好是 nlog2nnlog^2nnlog2n 的
這個(gè)題更像是縫合怪,里面的模型之前都做過(guò)類似的題目,但是結(jié)合起來(lái)就不會(huì)分析了,可以參考:
CodeForces - 1303E
中石油訓(xùn)練賽 - Watch Later
看完上面兩個(gè)題再回過(guò)頭來(lái)看這個(gè)題,可能會(huì)簡(jiǎn)單很多。
首先題目要求最小值的最大值,不難想到二分,這個(gè)題的重點(diǎn)是如何去 checkcheckcheck。
因?yàn)橥ㄟ^(guò)復(fù)雜度分析出來(lái)是狀壓dp了,我個(gè)人對(duì)狀壓dp的理解是,狀壓dp就是全排列問(wèn)題的一種優(yōu)化,所以狀壓dp可以解決的問(wèn)題,全排列暴力枚舉肯定也是可以解決的。所以先將問(wèn)題簡(jiǎn)化,如果本題放開(kāi)全排列,該如何去做呢?
全排列的本質(zhì)是確定了 nnn 的物品的一種順序,在 checkcheckcheck 函數(shù)中確定了順序后,該怎么去做呢。這里需要想到的一個(gè)點(diǎn)是,我們確定下來(lái)的這個(gè)順序,應(yīng)該轉(zhuǎn)換為在字符串中的順序。舉個(gè)例子,假設(shè)二分的長(zhǎng)度為 len=4len=4len=4,k=3k=3k=3,也就是說(shuō) “aaaa”,“bbbb”,“cccc” 這三個(gè)字符串應(yīng)該作為子串出現(xiàn)在原串中,而我們確定的順序,就是從頭開(kāi)始遍歷字符串,依次匹配到的順序。更具體的說(shuō),假如我們?nèi)帕忻杜e的順序是 3,1,23,1,23,1,2,那么在原串中,應(yīng)該先出現(xiàn) “cccc”,再出現(xiàn) “aaaa”,最后再出現(xiàn) “bbbb”
所以對(duì)于某個(gè)全排列確定的順序來(lái)說(shuō),我們貪心去匹配一定是最優(yōu)的,可以想象有一個(gè) endendend 指針一直在原串中后移,最后 check=truecheck=truecheck=true 的條件一定是 endendend 指針仍然在原串中
這個(gè)順序有什么用呢?類比于上面第一個(gè)題目的模型 CodeForces - 1303E,不難設(shè)計(jì)出狀壓dp的狀態(tài)了:dp[i]dp[i]dp[i] 代表的是,滿足狀態(tài) iii 下,endendend 指針的最小值,如果 dp[(1<<k)?1]dp[(1<<k)-1]dp[(1<<k)?1] 代表的位置仍在原串中,說(shuō)明 check=truecheck=truecheck=true
轉(zhuǎn)移的話預(yù)處理一個(gè)序列自動(dòng)機(jī)輔助轉(zhuǎn)移就可以了
其實(shí)這個(gè)題是一道不算難的題目,真的就是很多經(jīng)典模型拼湊起來(lái)的,感覺(jué)自己分析題目的能力還是欠缺很多
代碼:
// Problem: E. Stringforces // Contest: Codeforces - Educational Codeforces Round 111 (Rated for Div. 2) // URL: https://codeforces.com/contest/1550/problem/E // Memory Limit: 256 MB // Time Limit: 3000 ms // // Powered by CP Editor (https://cpeditor.org)// #pragma GCC optimize(2) // #pragma GCC optimize("Ofast","inline","-ffast-math") // #pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> #define lowbit(x) x&-x using namespace std; typedef long long LL; typedef unsigned long long ull; template<typename T> inline void read(T &x) {T f=1;x=0;char ch=getchar();while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();x*=f; } template<typename T> inline void write(T x) {if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0'); } const int inf=0x3f3f3f3f; const int N=1e6+100; char s[N]; int n,k,nt[N][17],dp[(1<<17)+100]; bool check(int len) {for(int i=0;i<17;i++) {nt[n+2][i]=nt[n+1][i]=n+2;}for(int c=0;c<k;c++) {int l=0;for(int i=n;i>=1;i--) {if(s[i]=='?'||s[i]-'a'==c) {l++;} else {l=0;}if(l>=len) {nt[i][c]=i+len;} else {nt[i][c]=nt[i+1][c];}}}for(int i=0;i<1<<k;i++) {dp[i]=n+2;}dp[0]=1;for(int i=0;i<1<<k;i++) {for(int j=0;j<k;j++) {if(((i>>j)&1)==0) {dp[i^(1<<j)]=min(dp[i^(1<<j)],nt[dp[i]][j]);}}}return dp[(1<<k)-1]<=n+1; } int main() { #ifndef ONLINE_JUDGE // freopen("data.in.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);read(n),read(k);scanf("%s",s+1);int l=0,r=n,ans=-1;while(l<=r) {int mid=(l+r)>>1;if(check(mid)) {ans=mid;l=mid+1;} else {r=mid-1;}}cout<<ans<<endl;return 0; }總結(jié)
以上是生活随笔為你收集整理的CodeForces - 1550E Stringforces(二分+状压dp)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: CodeForces - 1481E S
- 下一篇: CodeForces - 1476E P