• 编程之美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 }
  • 相关阅读:
    vue中创建全局单文件组件/命令
    export default与export的区别
    Android Fragment的使用(转载)
    ios 内存管理总结
    object-c 混编 调用C,C++接口
    Python3基础 yield send 获得生成器后,需要先启动一次
    Python3基础 yield next 获取生成器生出的值
    Python3基础 函数 无return、return 空或None 的效果相同
    Python3基础 函数 函数名赋值操作
    Python3基础 函数 函数名作为参数传给函数
  • 原文地址:https://www.cnblogs.com/njczy2010/p/4435240.html
Copyright © 2020-2023  润新知