[编程之美]回文字符序列

时间限制: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[i][j]表示s[i...j]之间的回文子序列的个数。

考虑dp[i][j]和dp[i][j - 1]的情况,dp[i][j]肯定包含dp[i][j - 1]的所有回文子序列。并且,当s[j]与s[i..j - 1]中的某个字符相同时,则会产生新的回文序列。

因此 dp[i][j] = dp[i][j - 1] + dp[k][j - 1] + 1, 其中s[k] == s[j - 1]。

考虑到需要遍历i, j, k三个下表,时间复杂度是o(n3),显然会超时。

参考其他人的题解,若s[j]与s[i + 1...j - 1]中的某个字符相同而产生的新的回文序列其实是已经包含在dp[i + 1][j]中,因此没有必要重复求解。

如果s[j] != s[i],那么dp[j][i] = dp[j][i - 1] + dp[j + 1][i] - dp[j + 1][i - 1]。此时回文序列分为三类,即包含s[j]的,包含s[i]的,以及都不包含的,根据集合原理可以得出解。

如果s[j] == s[i],此时dp[j][i] = dp[j][i - 1] + dp[j + 1][i] - dp[j + 1][i - 1] + dp[j + 1][i - 1] + 1,最后两项表示以s[i]和s[j]为两端组成的新的回文序列。

此时复杂度降为o(n2)

 

posted on 2015-04-19 13:48  风也轻云也淡  阅读(218)  评论(0编辑  收藏  举报