TJOI2018Party
題目描述
小豆參加了\(NOI\)的游園會(huì),會(huì)場(chǎng)上每完成一個(gè)項(xiàng)目就會(huì)獲得一個(gè)獎(jiǎng)?wù)?#xff0c;獎(jiǎng)?wù)?只會(huì)是\(N\), \(O\), \(I\)的字樣。在會(huì)場(chǎng)上他收集到了\(K\)個(gè)獎(jiǎng)?wù)陆M成的串。
兌獎(jiǎng)規(guī)則是獎(jiǎng)?wù)麓蛢丢?jiǎng)串的最長(zhǎng)公共子序列長(zhǎng)度為小豆最后獎(jiǎng)勵(lì)的等級(jí)。
現(xiàn)在已知兌獎(jiǎng)串長(zhǎng)度為\(N\),并且在兌獎(jiǎng)串上不會(huì)出現(xiàn)連續(xù)三個(gè)獎(jiǎng)?wù)聻?span id="ozvdkddzhkzd" class="math inline">\(NOI\),即獎(jiǎng)?wù)轮胁粫?huì)出現(xiàn)子串\(NOI\)。
現(xiàn)在小豆想知道各個(gè)獎(jiǎng)勵(lì)等級(jí)會(huì)對(duì)應(yīng)多少個(gè)不同的合法兌獎(jiǎng)串。
題解
我們可以先考忽略那些奇奇怪怪的限制條件,直接考慮如何統(tǒng)計(jì)序列數(shù)。
我們先考慮\(LCS\)的dp方法。
\[ dp[i][j]=max(dp[i-1][j],dp[i][j-1],dp[i-1][j-1]+(s[i]==t[j])) \]
我們?nèi)绻训诙S單獨(dú)拿出來考慮,我們可以發(fā)現(xiàn)第二維是一個(gè)單調(diào)不降的數(shù)列而且前后兩項(xiàng)的差是小于等于1的。
因?yàn)榈诙S的長(zhǎng)度非常小,所以我們可以把第二維差分之后狀壓起來作為我們的狀態(tài)。
而且有一個(gè)好處,我們知道了這個(gè)狀態(tài),就能發(fā)當(dāng)前\(dp\)值還原出來,假設(shè)我們知道了下一個(gè)字符時(shí)什么,我們就可以知道轉(zhuǎn)移后的狀態(tài)是什么了。
所以我們預(yù)處理\(g[i][j]\)表示當(dāng)前狀態(tài)為\(i\),新加入字符為\(j\),能夠轉(zhuǎn)移的狀態(tài)。
然后我們?cè)僭O(shè)\(dp[i][j][k]\)表示做到第\(i\)為,當(dāng)前狀態(tài)為\(j\),匹配到k個(gè)字符(這個(gè)是判斷那個(gè)特殊限制用的),隨便轉(zhuǎn)移一下就好了。
代碼
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int mod=1e9+7; int tran[200],g[3][1<<16],dp[2][1<<16][3],n,k,nw[20],a[20],ma,ans[20]; char s[20]; inline int rd(){int x=0;char c=getchar();bool f=0;while(!isdigit(c)){if(c=='-')f=1;c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}return f?-x:x; } inline void MOD(int &x){x=x>=mod?x-mod:x;} int main(){n=rd();k=rd();tran['N']=0;tran['O']=1;tran['I']=2;scanf("%s",s+1);for(int i=1;i<=k;++i)a[i]=tran[(int)s[i]];ma=(1<<k+1);for(int o=0;o<3;++o){for(int i=0;i<ma;++i){for(int j=0;j<=k;++j){nw[j]=(i&(1<<j))!=0;if(j)nw[j]+=nw[j-1]; }for(int j=k;j>=1;--j){nw[j]=max(nw[j],nw[j-1]);if(a[j]==o)nw[j]=max(nw[j],nw[j-1]+1);}for(int j=1;j<=k;++j)nw[j]=max(nw[j],nw[j-1]);int s=0;for(int j=k;j>=1;--j)nw[j]=nw[j]-nw[j-1];for(int j=0;j<=k;++j)s|=(1<<j)*nw[j];g[o][i]=s;}}int now=1,pre=0;dp[now][0][0]=1;for(int i=0;i<n;++i){swap(now,pre);memset(dp[now],0,sizeof(dp[now]));for(int j=0;j<ma;++j)for(int l=0;l<3;++l)if(dp[pre][j][l])for(int p=0;p<3;++p){int no=(p==l)?l+1:(p==0); if(no==3)continue;MOD(dp[now][g[p][j]][no]+=dp[pre][j][l]);}}for(int i=0;i<ma;++i){for(int j=0;j<=k;++j){nw[j]=(i&(1<<j))!=0;if(j)nw[j]+=nw[j-1];} MOD(ans[nw[k]]+=(1ll*dp[now][i][0]+dp[now][i][1]+dp[now][i][2])%mod);} for(int i=0;i<=k;++i)printf("%d\n",ans[i]);return 0; }轉(zhuǎn)載于:https://www.cnblogs.com/ZH-comld/p/10554475.html
總結(jié)
以上是生活随笔為你收集整理的TJOI2018Party的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jpg、gif、png-8、png-24
- 下一篇: MySQl的一些基本知识(1)