acm-(區間dp、迴文串、子序列)ICPC SG Preliminary Contest 2018 C - Making Palindromes

&*^*&(發表於2020-10-27

題面
kattis傳送門
vj傳送門
對於 s s s串而言,考慮設 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]表示所有長度為 l e n = j − i + 1 + k len=j-i+1+k len=ji+1+k的包含 s [ i ∼ j ] s[i\sim j] s[ij]的子串為子序列的迴文串的個數,其也等價於在 s [ i ∼ j ] s[i\sim j] s[ij]的基礎上再新增 k k k個任意字串使得字串成為一個迴文串的方案數,注意保證這些迴文串兩兩不同,那麼 d p [ 1 ] [ n ] [ n ] dp[1][n][n] dp[1][n][n]即為答案。假設串 s [ i ∼ j ] = X . . . Y , X ≠ Y s[i\sim j]=X...Y,X\ne Y s[ij]=X...Y,X=Y,那麼考慮這些符合條件的迴文串的特點,首先該回文串的兩端的字元可以是 26 26 26個字母中的任意一個,不過有兩個字母比較特殊,那就是 X X X Y Y Y,先考慮字母 A , A ≠ X , A ≠ Y A,A\ne X,A\ne Y A,A=X,A=Y,我們把 A A A字母填充到這個長為 l e n len len的迴文串兩端。如下圖所示:
圖一
由於我們要求 s [ i ∼ j ] s[i\sim j] s[ij]必須被包含在上圖所示的迴文串中,而目前位置1和位置 l e n len len都被一個既不是 X X X又不是 Y Y Y的字母所佔據,因此我們只能要求迴文串的 2 ∼ l e n − 1 2\sim len-1 2len1位置中包含 s [ i ∼ j ] s[i\sim j] s[ij],首先可以肯定上圖迴文串的 2 ∼ l e n − 1 2\sim len-1 2len1部分肯定也是一個迴文串,於是我們要求出一個長度為 l e n − 2 len-2 len2的包含 s [ i ∼ j ] s[i\sim j] s[ij]作為子序列的迴文串的個數,它等於 d p [ i ] [ j ] [ k − 2 ] dp[i][j][k-2] dp[i][j][k2]

不過當 A = X A=X A=X的時候,如下圖所示:
圖二
由於是左邊的 X X X已經與 s [ i ] s[i] s[i]相同,因此我們可以發現只要求上圖迴文串的 2 ∼ l e n − 1 2\sim len-1 2len1位置包含 s [ i + 1 ∼ j ] s[i+1\sim j] s[i+1j]作為子序列即可,注意這個條件是個充要條件。如果你要問為什麼不可以包含 s [ i ∼ j ] s[i\sim j] s[ij]作為子序列,其實只要稍加思考可以發現 s [ i + 1 ∼ j ] s[i+1\sim j] s[i+1j]本身就是 s [ i ∼ j ] s[i\sim j] s[ij]的子序列,我們求出包含 s [ i + 1 ∼ j ] s[i+1\sim j] s[i+1j]作為子序列的迴文串,自然也會包含所有可能的以 s [ i ∼ j ] s[i\sim j] s[ij]作為子序列的迴文串。不過你不能讓條件變為包含 s [ i + 2 ∼ j ] s[i+2\sim j] s[i+2j]作為子序列,這樣顯然是不能通過一個 X X X轉移到 s [ i ∼ j ] s[i\sim j] s[ij]的。

那麼迴文串 2 ∼ l e n − 1 2\sim len-1 2len1包含 s [ i + 1 ∼ j ] s[i+1\sim j] s[i+1j]作為子序列的方案數其實就是 d p [ i + 1 ] [ j ] [ k − 1 ] dp[i+1][j][k-1] dp[i+1][j][k1]

如果將 X X X換成 Y Y Y也是同樣地道理。

於是我們可以將這些狀態加起來,得到 d p [ i ] [ j ] [ k ] = d p [ i + 1 ] [ j ] [ k − 1 ] + d p [ i ] [ j − 1 ] [ k − 1 ] + 24 d p [ i ] [ j ] [ k − 2 ] dp[i][j][k]=dp[i+1][j][k-1]+dp[i][j-1][k-1]+24dp[i][j][k-2] dp[i][j][k]=dp[i+1][j][k1]+dp[i][j1][k1]+24dp[i][j][k2]

對於 s [ i ∼ j ] = X . . . X s[i\sim j]=X...X s[ij]=X...X的情況其實也就不難推了,跟上面相同,分類討論一下即可,這裡只有兩種情況,要麼最兩端字母不為 X X X,有25種情況,要麼最兩端字母為 X X X,這種情況單獨考慮,於是總方程為 d p [ i ] [ j ] [ k ] = d p [ i + 1 ] [ j − 1 ] [ k ] + 25 d p [ i ] [ j ] [ k − 2 ] dp[i][j][k]=dp[i+1][j-1][k]+25dp[i][j][k-2] dp[i][j][k]=dp[i+1][j1][k]+25dp[i][j][k2]

不過還有一些邊界條件需要處理。
k < 0 k<0 k<0時,這時候意味著沒辦法新增字元,這時候方案數一定為0。

i > j i>j i>j時,這時候我們只需要新增 k k k個任意字元就是所有的方案數,由於是迴文串,只需要決定前 ⌋ k 2 ⌋ \rfloor \frac k2\rfloor 2k個字元就可以決定整個迴文串,因此方案數為 2 ⌋ k 2 ⌋ 2^{\rfloor \frac k2\rfloor} 22k

i = j i=j i=j時,這時候我們可不能當成 s [ i ∼ j ] = X . . . X s[i\sim j]=X...X s[ij]=X...X的這種情況處理,因為在這種情況下你在迴文串兩端新增一個 X X X就能成功契合 s [ i ∼ j ] s[i\sim j] s[ij]兩端的 X X X,但 i = j i=j i=j時其實只有一個 X X X,所以需要特判。這裡直接容斥即可,由於迴文串長度為 k + 1 k+1 k+1,如果無限制的話總方案數為 2 6 ⌊ k + 1 2 ⌋ 26^{\lfloor \frac {k+1}2\rfloor} 262k+1,然後除去其中不包含 s [ i ] s[i] s[i]的迴文串,這些迴文串有 2 5 ⌊ k + 1 2 ⌋ 25^{\lfloor \frac {k+1}2\rfloor} 252k+1個,剩下的就是包含至少一個 s [ i ] s[i] s[i]的迴文串。

這裡給出一份參考程式碼:

int dp[maxn][maxn][maxn];
char s[maxn];

inline int dfs(int i,int j,int k){
	if(k<0)return 0;
	if(~dp[i][j][k])return dp[i][j][k];
	register int &ans=dp[i][j][k];
	if(i>j)ans=qpow(26,k+1>>1,mod);
	else if(i==j)ans=sub(qpow(26,k+2>>1,mod),qpow(25,k+2>>1,mod));
	else if(s[i]==s[j])ans=sum(dfs(i+1,j-1,k),25ll*dfs(i,j,k-2)%mod);
	else ans=sum(sum(dfs(i+1,j,k-1),dfs(i,j-1,k-1)),24ll*dfs(i,j,k-2)%mod);
	return ans;
}
int main(){
	int n=rd();
	if(!n)return wrn(1),0;
	rds(s+1);
	FOR(i,0,n+2)
	FOR(j,0,n+2)
	FOR(k,0,n+1)dp[i][j][k]=-1;
	wrn(dfs(1,n,n));
} 

相關文章