编程之美2015资格赛 题目2 : 回文字符序列 [ 区间dp ]

传送门

题目2 : 回文字符序列

时间限制: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,搞了好久。。。晕死,最后用的是记忆化dp,没想到递推肿么搞。

看了网上的代码后,发现:我的思路还是有偏差。

递推的转移方程应该为:

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;

结果:AC | NA    提交时间:2015-04-17 16:05:34

贴一份其他人ac的代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 
 5 using namespace std;
 6 
 7 const int maxn = 1100;
 8 char s[maxn];
 9 const int mod = 100007;
10 int dp[maxn][maxn];
11 
12 int solve()
13 {
14     memset(dp, 0, sizeof(dp));
15     int n = strlen(s);
16     
17     for (int l = 0; l <= n; ++l)
18     {
19         for (int i = 0; i + l < n; ++i)
20         {
21             int j = i + l;
22             if (s[i] == s[j])
23                 dp[i][j] = (dp[i + 1][j] + dp[i][j - 1] + 1) % mod;
24             else
25                 dp[i][j] = (dp[i + 1][j] + dp[i][j - 1] - dp[i + 1][j - 1]) % mod;
26         }
27     }
28     
29     return (dp[0][n - 1]%mod + mod)%mod;
30 }
31 
32 int main()
33 {
34     int T;
35     cin >> T;
36     for (int cas = 1; cas <= T; ++cas)
37     {
38         cin >> s;
39         printf("Case #%d: %d
", cas, solve());
40     }
41     return 0;
42 }
View Code

再贴一发记忆化dp ac的代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <map>
 5 #include <algorithm>
 6 using namespace std;
 7 
 8 #define mxn 200005
 9 #define LL long long
10 #define MP make_pair
11 #define REP(i, a, b) for (int i = a; i <= b; ++i)
12 #define FOR(i, a, b) for (int i = a; i < b; ++i)
13 
14 #define mod 100007
15 
16 int dp[1005][1005];
17 char s[1005];
18 
19 int F(int l, int r) {
20     if (dp[l][r] != -1) return dp[l][r];
21     if (l > r) return dp[l][r] = 0;
22     if (l == r) return dp[l][r] = 1;
23     int& ret = dp[l][r];
24     ret = (F(l + 1, r) + F(l, r - 1)) % mod;
25     if (s[l] == s[r]) ++ret;
26     else ret -= F(l + 1, r - 1);
27     ret = (ret + mod) % mod;
28     return ret;
29 }
30 
31 int main()
32 {
33     int cas = 0, t;
34 
35     scanf("%d", &t);
36     while (t--) {
37         memset(dp, -1, sizeof(dp));
38         scanf("%s", s + 1);
39         int ans = F(1, strlen(s + 1));
40         printf("Case #%d: %d
", ++cas, ans);
41     }
42     return 0;
43 }
View Code


我的思路复杂度不好,T了

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <stack>
 4 #include <vector>
 5 #include <algorithm>
 6 #include <queue>
 7 #include <map>
 8 #include <string>
 9 #include <cmath>
10 
11 #define ll long long
12 int const N = 1005;
13 int const M = 205;
14 int const INF = 0x7fffffff;
15 int const mod = 100007;
16 
17 using namespace std;
18 
19 int T,cnt;
20 int dp[N][N];
21 char s[N];
22 int l;
23 int ans;
24 
25 void ini()
26 {
27     scanf("%s",s+1);
28     l=strlen(s+1);
29     memset(dp,-1,sizeof(dp));
30 }
31 
32 int dfs(int st,int en)
33 {
34     if(dp[st][en]!=-1) return dp[st][en];
35     if(st>en){
36         return dp[st][en]=0;
37     }
38     if(st==en){
39         return dp[st][en]=1;
40     }
41     dp[st][en]=dfs(st,en-1)+1;
42    // printf(" st=%d en=%d dp=%d
",st,en,dp[st][en]);
43 
44     int i;
45     for(i=st;i<en;i++){
46         if(s[i]==s[en])
47             dp[st][en]=(dp[st][en]+dfs(i+1,en-1)+1)%mod;
48     }
49     return dp[st][en];
50 }
51 
52 void solve()
53 {
54     ans=dfs(1,l);
55 }
56 
57 void out()
58 {
59 /*
60     int i,j;
61     for(i=1;i<=l;i++){
62         for(j=i;j<=l;j++){
63             printf(" i=%d j=%d dp=%d
",i,j,dp[i][j]);
64         }
65     }*/
66     printf("Case #%d: %d
",cnt,ans);
67 }
68 
69 int main()
70 {
71     //freopen("data.in","r",stdin);
72     scanf("%d",&T);
73     for(cnt=1;cnt<=T;cnt++)
74    // while(T--)
75     //while(scanf("%d%d",&n,&m)!=EOF)
76     {
77         ini();
78         solve();
79         out();
80     }
81 
82     return 0;
83 }