HDU4632 Palindrome subsequence(区间DP)
Description
In mathematics, a subsequence is a sequence that can be derived from another sequence by deleting some elements without changing the order of the remaining elements. For example, the sequence <A, B, D> is a subsequence of <A, B, C, D, E, F>.
Given a string S, your task is to find out how many different subsequence of S is palindrome. Note that for any two subsequence X = <Sx1, Sx2, …, Sxk> and Y = <Sy1, Sy2, …, Syk> , if there exist an integer i (1<=i<=k) such that xi != yi, the subsequence X and Y should be consider different even if Sxi = Syi. Also two subsequences with different length should be considered different.
Input
The first line contains only one integer T (T<=50), which is the number of test cases. Each test case contains a string S, the length of S is not greater than 1000 and only contains lowercase letters.
Output
For each test case, output the case number first, then output the number of different subsequence of the given string, the answer should be module 10007.
Sample Input
4
a
aaaaa
goodafternooneveryone
welcometoooxxourproblems
Sample Output
Case 1: 1
Case 2: 31
Case 3: 421
Case 4: 960
题意
给定一个字符串,求字符串中不同回文子序列的个数。dp[i][j]表示从i到j的不同回文子序列的个数。
#include<iostream>#include<string>#include<cstring>#include<cmath>#include<algorithm>#include<cstdio>#include<queue>#include<stack>#include<vector>#include<functional>#include<map>using namespace std;typedef long long ll;const int N=1e6+10,NN=2e3+10,INF=0x3f3f3f3f;const ll MOD=1e9+7;int len;int dp[NN][NN];char str[N];void init(){for(int i=1;i<=len;i++){for(int j=1;j<=len;j++){if(i==j) dp[i][j]=1;else dp[i][j]=0;}}}int main(){int t,T=0;scanf(\"%d\",&t);while(t--){scanf(\"%s\",str+1);len=strlen(str+1);init();for(int l=2;l<=len;l++){//枚举区间长度for(int i=1;i<=len-l+1;i++){//枚举左边界int j=i+l-1;//计算右边界if(str[i]==str[j]) dp[i][j]=(dp[i+1][j]+dp[i][j-1]+1)%10007;//原方程为dp[i][j]=dp[i+1][j]+dp[i][j-1]-dp[i+1][j-1]+1+dp[i+1][j-1]。这里好理解了,加上单独取i和j,取i和j之后取中间的部分就不存在重复啦else dp[i][j]=(dp[i+1][j]+dp[i][j-1]-dp[i+1][j-1]+10007)%10007;//表示取i到j-1和i+1到减掉i+1到j-1的部分,因为中间加了两次}}printf(\"Case %d: %d\\n\",++T,dp[1][len]);}}