HDU4632 Palindrome subsequence 題解 區間DP

題目連接:http://acm.hdu.edu.cn/showproblem.php?pid=4632
【題目描述】
《迴文子串數量》
給你一個長度爲N(N≤1000)的字符串,你輸出它全部的迴文子串的數量(對10007取模)。
只要從字符串 s 中順序地取出一些字符(不要求連續,能夠是 s 自己,不能是空串),不改變他們的順序的狀況下,這個子串是一個迴文串,那麼他就是一個 s 的迴文子串。
【輸入格式】
首先是一個數T(T≤50),表示測試用例的數量。
接下來T行,每行包含一個字符串。
【輸出格式】
對於每個字符串,你須要輸出它的迴文子串數量(因爲數據量可能會比較大,因此結果須要對10007取模)。
【樣例輸入】
4
a
aaaaa
goodafternooneveryone
welcometoooxxourproblems
【樣例輸出】
Case 1: 1
Case 2: 31
Case 3: 421
Case 4: 960
【題目分析】
涉及的知識點:區間動態規劃(區間DP)。
首先咱們假設 dp[i][j] 表示字符串 s 的子串 s[i..j] 中包含的迴文子串的數量。
咱們能夠獲得:
· 當i<j且s[i]!=s[j]時, dp[i][j] = dp[i][j-1] ∪ dp[i+1][j] (這裏「∪」符號表示)兩個集合的並,
根據容斥原理,咱們能夠獲得:
  dp[i][j] = dp[i][j-1] ∪ dp[i+1][j] = dp[i][j-1] + dp[i+1][j] - dp[i+1][j-1]
· 當i<j且s[i]==s[j]時,dp[i][j]的構成除了上述部分之外,還有 s[i] + s' + s[j] 部分,其中 s' 表示 s[i+1..j-1] 中的任意一個迴文串 加上一個特殊的空字符串
因此此時:
  dp[i][j] = dp[i][j-1] ∪ dp[i+1][j] + dp[i+1][j-1] + 1 = dp[i][j-1] + dp[i+1][j] + 1
假設字符串的長度爲n,座標從0開始,那麼咱們最終的答案就是 dp[0][n-1]。
須要注意的一些細節:
由於這裏在運算的時候可能會出現負數,因此比較好的解決辦法是加上一個 MOD 在進行取模操做,就不會出現負數了。
據此,咱們能夠編寫代碼以下:php

 

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
#define MOD 10007
const int maxn = 1001;
int T, n, dp[maxn][maxn];
string s;

int main() {
    cin >> T;
    for (int cas = 1; cas <= T; cas ++) {
        cin >> s;
        n = s.length();
        fill(dp[0], dp[0]+maxn*maxn, 0);
        for (int l = 1; l <= n; l ++) {
            for (int i = 0; i+l-1 < n; i ++) {
                int j = i + l - 1;
                if (l == 1) dp[i][j] = 1;
                else if (s[i] == s[j]) dp[i][j] = (dp[i][j-1] + dp[i+1][j] + 1) % MOD;
                else {
                    dp[i][j] = (dp[i][j-1] + dp[i+1][j] + MOD - (l > 2 ? dp[i+1][j-1] : 0)) % MOD;
                }
            }
        }
        cout << "Case " << cas << ": " << dp[0][n-1] << endl;
    }
    return 0;
}
相關文章
相關標籤/搜索