dp套dp學習筆記(P4590 [TJOI2018]遊園會題解)
阿新 • • 發佈:2021-03-25
# dp套dp學習筆記(P4590 [TJOI2018]遊園會題解)
## 分析
題目的意思是對於每一個 $i$ 求滿足如下條件的字串的數目:
$1$.長度為 $n$ 且只出現過'N','O','I'三種字元。
$2$.和一個長度為 $k$ 的模式串的最長公共子序列長度恰好為 $i$。
$3$.不含"NOI"這個子串。
發現第一個限制和第三個限制比較好滿足,直接 $dp$ 的時候記一下當前匹配到了 $NOI$ 這個字串的第幾個字元即可。
對於第二個限制,我們似乎需要知道當前的字串每一位填了什麼數才可以求出它和模式串的最長公共子序列。
但是仔細想一下又會發現不同的公共子序列只有 $2^k$ 種,所以我們只需要狀壓當前的串已經匹配好的位置的狀態即可。
轉移的時候我們需要對於每一種匹配的狀態分別求出它加上三種不同的字元之後達到的新的匹配的狀態。
這個東西可以提前用一次 $dp$ 預處理出來。
轉移的時候用我們預處理出來的狀態直接轉移即可。
大概可以理解為將內層 $dp$ 的結果作為外層 $dp$ 的狀態進行 $dp$。
## 程式碼
``` cpp
#include
#include
#include
#include
#include
#define rg register
inline int read(){
rg int x=0,fh=1;
rg char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*fh;
}
const int mod=1e9+7,maxn=4e4+5;
int nxt[maxn][3],f[2][maxn][3],dp[maxn][2],n,m,a[maxn],mmax,siz[maxn],ans[maxn];
char s[maxn];
inline int addmod(rg int now1,rg int now2){
return now1+=now2,now1>=mod?now1-mod:now1;
}
void pre(){
for(rg int i=0;i<=mmax;i++){
for(rg int k=1;k<=m;k++) dp[k][0]=dp[k-1][0]+((i>>(k-1))&1);
for(rg int j=0;j<=2;j++){
for(rg int k=1;k<=m;k++){
dp[k][1]=std::max(dp[k-1][1],dp[k][0]);
if(a[k]==j) dp[k][1]=std::max(dp[k][1],dp[k-1][0]+1);
}
rg int zt=0;
for(rg int k=1;k<=m;k++) if(dp[k][1]>dp[k-1][1]) zt|=(1<<(k-1));
nxt[i][j]=zt;
}
}
}
int main(){
n=read(),m=read();
scanf("%s",s+1);
for(rg int i=1;i<=m;i++){
if(s[i]=='O') a[i]=1;
else if(s[i]=='I') a[i]=2;
}
mmax=(1<>1]+(i&1);
pre();
rg int now=1;
f[0][0][0]=1;
for(rg int i=1;i<=n;i++){
now^=1;
for(rg int j=0;j<=mmax;j++){
for(rg int k=0;k<=2;k++){
f[now^1][j][k]=0;
}
}
for(rg int j=0;j<=mmax;j++){
for(rg int k=0;k<=2;k++){
if(f[now][j][k]){
if(k==0){
f[now^1][nxt[j][0]][1]=addmod(f[now^1][nxt[j][0]][1],f[now][j][k]);
f[now^1][nxt[j][1]][0]=addmod(f[now^1][nxt[j][1]][0],f[now][j][k]);
f[now^1][nxt[j][2]][0]=addmod(f[now^1][nxt[j][2]][0],f[now][j][k]);
} else if(k==1){
f[now^1][nxt[j][1]][2]=addmod(f[now^1][nxt[j][1]][2],f[now][j][k]);
f[now^1][nxt[j][0]][1]=addmod(f[now^1][nxt[j][0]][1],f[now][j][k]);
f[now^1][nxt[j][2]][0]=addmod(f[now^1][nxt[j][2]][0],f[now][j][k]);
} else {
f[now^1][nxt[j][0]][1]=addmod(f[now^1][nxt[j][0]][1],f[now][j][k]);
f[now^1][nxt[j][1]][0]=addmod(f[now^1][nxt[j][1]][0],f[now][j][k]);
}
}
}
}
}
now^=1;
for(rg int i=0;i<=mmax;i++){
ans[siz[i]]=addmod(addmod(ans[siz[i]],f[now][i][0]),addmod(f[now][i][1],f[now][i][2]));
}
for(rg int i=0;i<=m;i++){
printf("%d\n",ans[i]);
}
return