acm-(區間dp、迴文串、子序列)ICPC SG Preliminary Contest 2018 C - Making Palindromes
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=j−i+1+k的包含
s
[
i
∼
j
]
s[i\sim j]
s[i∼j]的子串為子序列的迴文串的個數,其也等價於在
s
[
i
∼
j
]
s[i\sim j]
s[i∼j]的基礎上再新增
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[i∼j]=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[i∼j]必須被包含在上圖所示的迴文串中,而目前位置1和位置
l
e
n
len
len都被一個既不是
X
X
X又不是
Y
Y
Y的字母所佔據,因此我們只能要求迴文串的
2
∼
l
e
n
−
1
2\sim len-1
2∼len−1位置中包含
s
[
i
∼
j
]
s[i\sim j]
s[i∼j],首先可以肯定上圖迴文串的
2
∼
l
e
n
−
1
2\sim len-1
2∼len−1部分肯定也是一個迴文串,於是我們要求出一個長度為
l
e
n
−
2
len-2
len−2的包含
s
[
i
∼
j
]
s[i\sim j]
s[i∼j]作為子序列的迴文串的個數,它等於
d
p
[
i
]
[
j
]
[
k
−
2
]
dp[i][j][k-2]
dp[i][j][k−2]。
不過當
A
=
X
A=X
A=X的時候,如下圖所示:
由於是左邊的
X
X
X已經與
s
[
i
]
s[i]
s[i]相同,因此我們可以發現只要求上圖迴文串的
2
∼
l
e
n
−
1
2\sim len-1
2∼len−1位置包含
s
[
i
+
1
∼
j
]
s[i+1\sim j]
s[i+1∼j]作為子序列即可,注意這個條件是個充要條件。如果你要問為什麼不可以包含
s
[
i
∼
j
]
s[i\sim j]
s[i∼j]作為子序列,其實只要稍加思考可以發現
s
[
i
+
1
∼
j
]
s[i+1\sim j]
s[i+1∼j]本身就是
s
[
i
∼
j
]
s[i\sim j]
s[i∼j]的子序列,我們求出包含
s
[
i
+
1
∼
j
]
s[i+1\sim j]
s[i+1∼j]作為子序列的迴文串,自然也會包含所有可能的以
s
[
i
∼
j
]
s[i\sim j]
s[i∼j]作為子序列的迴文串。不過你不能讓條件變為包含
s
[
i
+
2
∼
j
]
s[i+2\sim j]
s[i+2∼j]作為子序列,這樣顯然是不能通過一個
X
X
X轉移到
s
[
i
∼
j
]
s[i\sim j]
s[i∼j]的。
那麼迴文串 2 ∼ l e n − 1 2\sim len-1 2∼len−1包含 s [ i + 1 ∼ j ] s[i+1\sim j] s[i+1∼j]作為子序列的方案數其實就是 d p [ i + 1 ] [ j ] [ k − 1 ] dp[i+1][j][k-1] dp[i+1][j][k−1]。
如果將 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][k−1]+dp[i][j−1][k−1]+24dp[i][j][k−2]。
對於 s [ i ∼ j ] = X . . . X s[i\sim j]=X...X s[i∼j]=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][j−1][k]+25dp[i][j][k−2]。
不過還有一些邊界條件需要處理。
當
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} 2⌋2k⌋。
當 i = j i=j i=j時,這時候我們可不能當成 s [ i ∼ j ] = X . . . X s[i\sim j]=X...X s[i∼j]=X...X的這種情況處理,因為在這種情況下你在迴文串兩端新增一個 X X X就能成功契合 s [ i ∼ j ] s[i\sim j] s[i∼j]兩端的 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} 26⌊2k+1⌋,然後除去其中不包含 s [ i ] s[i] s[i]的迴文串,這些迴文串有 2 5 ⌊ k + 1 2 ⌋ 25^{\lfloor \frac {k+1}2\rfloor} 25⌊2k+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));
}
相關文章
- 迴文串問題(動態規劃DP C++)動態規劃C++
- 求迴文子序列個數(雖然字串,但是DP)字串
- AtCoder Regular Contest 104——C區間dp
- 杭電OJ2029迴文串——Palindromes _easy version(C語言解析)C語言
- 程式碼隨想錄day46 || 647 迴文子串, 516 最長迴文子序列
- NOIP2015子串[序列DP]
- Codeforces 245H Queries for Number of Palindromes:區間dp
- java 最長迴文子串Java
- Prime Palindromes( 素數迴文) C++實現C++
- 線性dp:LeetCode516 .最長迴文子序列LeetCode
- 程式碼隨想錄演算法訓練營 | 647. 迴文子串,516.最長迴文子序列演算法
- Codeforces 163A Substring and Subsequence:dp【子串與子序列匹配】
- 今日面試題:最長迴文子串;及迴文分割分析面試題
- 演算法-兩最長迴文子串演算法
- LEECODE 5 求最長迴文子串
- lc1771 由子序列構造的最長迴文串的長度
- 程式碼隨想錄演算法訓練營day46| 647. 迴文子串 516.最長迴文子序列演算法
- (迴文串)leetcode各種迴文串問題LeetCode
- [動態規劃] 六、最長迴文子串動態規劃
- LeetCode 5.最長迴文子串LeetCode
- 演算法之字串——最長迴文子串演算法字串
- Amazon面試題:尋找最長迴文子串面試題
- 程式碼隨想錄演算法訓練營第五十七/天 | 516. 最長迴文子序列,647. 迴文子串演算法
- Leetcode[字串] 5. 最長迴文子串LeetCode字串
- LeetCode-5. 最長迴文子串(Manacher)LeetCode
- 翻譯數字串;及最長迴文子串分析字串
- 線性dp:最長公共子串
- 子序列與子串問題總結
- 最長迴文子串 V2(Manacher演算法)演算法
- 區間dp
- LeetCode516. 最長迴文子序列LeetCode
- 每日一道 LeetCode (48):最長迴文子串LeetCode
- [LeetCode] Longest Palindromic Substring 最長迴文子串LeetCode
- ural 1297 最長迴文子串 字尾陣列陣列
- 【DP】區間DP入門
- 線性dp:最長上升子序列
- 線性dp:最長公共子序列
- 動態規劃解最長迴文子序列並優化空間複雜度動態規劃優化複雜度