您的位置:首页 > 其它

hihocoder 1149 : 回文字符序列(区间dp)

2016-04-11 22:39 337 查看

题意

时间限制:2000ms
单点时限:1000ms
内存限制:256MB


描述

给定字符串,求它的回文子序列个数。回文子序列反转字符顺序后仍然与原序列相同。例如字符串aba中,回文子序列为”a”, “a”, “aa”, “b”, “aba”,共5个。内容相同位置不同的子序列算不同的子序列。

输入

第一行一个整数T,表示数据组数。之后是T组数据,每组数据为一行字符串。

输出

对于每组数据输出一行,格式为”Case #X: Y”,X代表数据编号(从1开始),Y为答案。答案对100007取模。

数据范围
1 ≤ T ≤ 30

小数据

字符串长度 ≤ 25

大数据

字符串长度 ≤ 1000


样例输入

5
aba
abcbaddabcba
12111112351121
ccccccc
fdadfa


样例输出

Case #1: 5
Case #2: 277
Case #3: 1333
Case #4: 127
Case #5: 17


思路

典型的区间dp.

if(s[i] == s[j])
dp[i][j] = dp[i+1][j]+dp[i][j-1]+1;
else
dp[i][j] = dp[i+1][j]+dp[i][j-1]-dp[i+1][j-1];


简单解释一下,先说一下s[i] != s[j]时,dp[i+1][j]+dp[i][j-1]然后再减去重复的dp[i+1][j-1]部分,这个不难理解。

那么当s[i] == s[j]时,显然i与j之间所有是回文串的子序列可以用s[i],s[j]包裹成为新的子序列,所以重复部分不需要剪去了,还需要加上1是因为s[i]s[j]两个单独一起也可以作为一个回文子序列。

代码

#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>

using namespace std;

const int MOD = 100007;
char s[1009];
int dp[1009][1009];

int main()
{
int T;
scanf("%d", &T);
for(int i=1; i<=T; i++)
{
memset(dp, 0, sizeof(dp));
scanf("%s", s+1);
int n = strlen(s+1);
for(int l=0; l<n; l++)
{
for(int i=1; i+l<=n; i++)
{
int j = i+l;
if(s[i] == s[j])
dp[i][j] = (dp[i+1][j]+dp[i][j-1]+1)%MOD;
else
dp[i][j] = (dp[i+1][j]+dp[i][j-1]-dp[i+1][j-1]+MOD)%MOD;
}
}
printf("Case #%d: %d\n", i, dp[1]
);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: