hdu 4632 Palindrome Subsequence
技術標籤:動態規劃
題目連結
定義:dp[i] [j]為字串第i個字元到第j個字元所含迴文子序列的數量
思路:此題用了區間DP的方法。先從小問題開始考慮,由於已知一個由單個字母組成的字串他的子字串必定只有一個,對於每一個字串,我們要讓他的規模擴大都需要在他的頭或尾加上一個字母,所以我們可以將問題從單字元組成的字串擴大到任意長度的字串。因此,在我們求一個字串有多少個迴文子序列的時候,可以將問題拆分為求兩個次大的字串,即最長字串去掉頭尾的子字串的迴文子序列的問題。
對於字串IJ,由於去掉開頭第一個元素和末尾第一個元素所造成的影響是不同的,所以dp[i][j] = dp[i+1][j]+dp[i
f
(
x
)
=
{
d
p
[
i
+
1
]
[
j
]
+
d
p
[
i
]
[
j
−
1
]
−
d
p
[
i
+
1
]
[
j
−
1
]
s[i]!=s[j]
d
p
[
i
+
1
]
[
j
]
+
d
p
[
i
]
[
j
−
1
]
+
1
s[i]==s[j]
f(x)=\left\{ \begin{aligned} dp[i+1][j]+dp[i][j-1]-dp[i+1][j-1]\:\:\:\:\:\:& \text{s[i]!=s[j]}\\ dp[i+1][j]+dp[i][j-1] +1\:\:\:\:\:\:& \text{s[i]==s[j]} \end{aligned} \right.
題目要求對10007取模,在式子中應注意這一點,有減法的式子中應該加上一個10007避免得到負數。
程式碼:
#include<cmath>
#include<stack>
#include<cstdio>
#include<queue>
#include<vector>
#include<map>
#include<set>
#include<iostream>
#include<string>
#include<sstream>
#include<algorithm>
#include<string.h>
typedef long long ll;
using namespace std;
inline int read() {
int s = 0, w = 1;
char ch = getchar();
while (ch < '0' || ch>'9') { if (ch == '-')w = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * w;
}//快讀
const int M = 1005;
const int MOD = 10007;
int dp[M][M];
int main()
{
int T;
string s;
scanf("%d",&T);
getchar();
for(int t=1;t<=T;t++){
memset(dp,0,sizeof(dp));
getline(cin,s);
int ans=0,n=s.length();
for(int i=0;i<n;i++) dp[i][i]=1;
for(int len=1;len<n;len++){
for(int i=0;i+len<n;i++){
int j=i+len;
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]-dp[i+1][j-1]+MOD)%MOD;
}
}
printf("Case %d: %d\n",t,dp[0][n-1]);
}
return 0;
}