zoukankan      html  css  js  c++  java
  • 编程之美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 }
  • 相关阅读:
    Java实现 蓝桥杯VIP 算法训练 字符删除
    Java实现 蓝桥杯VIP 算法训练 字符删除
    Java实现 蓝桥杯VIP 算法训练 字符删除
    Java实现 蓝桥杯VIP 算法训练 字符删除
    Java实现 蓝桥杯VIP 算法训练 字符删除
    Java实现 蓝桥杯VIP 算法训练 字符串编辑
    Java实现 蓝桥杯VIP 算法训练 字符串编辑
    Java实现 蓝桥杯VIP 算法训练 字符串编辑
    Java实现 蓝桥杯VIP 算法训练 字符串编辑
    Java实现 蓝桥杯VIP 算法训练 字符串编辑
  • 原文地址:https://www.cnblogs.com/njczy2010/p/4435240.html
Copyright © 2011-2022 走看看