• SCUT125 华为杯 D.笔芯回文 —— DP


    题目链接: https://scut.online/p/125


    题目描述

    bxbx有一个长度一个字符串SS,bxbx可以对其进行若干次操作。

    每次操作可以删掉一个长度为k(1 leq k leq n)k(1kn)的连续回文子串,bxbx获得a_kak​​的愉悦值。

    一个字符串是回文串当且仅当正读和反读都是一样的。例如"a", "aa", "abcba""a","aa","abcba"是回文串,"ab", "abc","aabab""ab","abc","aabab"不是回文串。

    字符串删除之后相邻的字符不会合并在一起。

    现在,bxbx想知道他最多能获得多少愉悦值。

    输入格式

    输入第一行一个整数TT,表示数据组数。

    对于每组数据,第一行一个整数nn。

    第二行nn个整数,第ii个表示a_iai​​。

    第三行为字符串SS。

    1 leq T leq 201T20

    1 leq n leq |S| leq 50001nS5000

    0 leq a_i leq 10000000000ai​​1000000000

    SS只包括小写字母。

    输出格式

    对每组数据,输出bxbx所能获得的最大愉悦值。

    样例数据

    输入

    2
    3
    1 2 3
    aba
    3
    3 2 1
    aba

    输出

    3
    9

    题解:

    1.ok[l][r]代表区间l~r的子串是否为回文串,O(n^2)预处理。

    2. dp[i]代表删除前i个字符的最大价值, 状态转移方程为:if(ok[j][i])  dp[i] = max(dp[i],dp[j-1]+a[i-j+1]);


    代码如下:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define ms(a, b)  memset((a), (b), sizeof(a))
     4 typedef long long LL;
     5 const int INF = 2e9;
     6 const LL LNF = 9e18;
     7 const int mod = 1e9+7;
     8 const int maxn = 5000+10;
     9 
    10 char s[maxn];
    11 LL a[maxn], dp[maxn];
    12 bool ok[maxn][maxn];
    13 
    14 int n, len;
    15 
    16 void init()
    17 {
    18     ms(ok,0);
    19     ms(dp,0);
    20 
    21     for(int i = 1; i<=len; i++)
    22     {
    23         int l = i, r = i;
    24         while(l>=1 && r<=len && (r-l+1)<=n && s[l]==s[r])
    25             ok[l--][r++] = 1;
    26     }
    27 
    28     for(int i = 1; i<=len; i++)
    29     {
    30         int l = i, r = i+1;
    31         while(l>=1 && r<=len && (r-l+1)<=n && s[l]==s[r])
    32             ok[l--][r++] = 1;
    33     }
    34 }
    35 
    36 void solve()
    37 {
    38     for(int i = 1; i<=len; i++)
    39     for(int j = 1; j<=i; j++)
    40     {
    41         if(ok[j][i])
    42             dp[i] = max(dp[i],dp[j-1]+a[i-j+1]);
    43     }
    44 
    45     printf("%lld
    ",dp[len]);
    46 }
    47 
    48 int main()
    49 {
    50     int T;
    51     scanf("%d",&T);
    52     while(T--)
    53     {
    54         scanf("%d",&n);
    55         for(int i = 1; i<=n; i++)
    56             scanf("%lld",&a[i]);
    57 
    58         scanf("%s", s+1);
    59         len = strlen(s+1);
    60 
    61         init();
    62         solve();
    63     }
    64     return 0;
    65 }
    View Code
  • 相关阅读:
    set
    皮肤病药物
    C 批量保存图片进 mysql 利用MYSQL_BIND插入longblob
    eclipse行号显示
    dynamic_cast使用
    list添加删除操作
    VS2008 对齐代码
    c++ mysql二进制存取,blob存取
    Select Window关键字——模拟打开了多个页面窗口时,在不同的窗口之间,进行窗口切换
    Click Image关键字——模拟单击某一个图片 其余:Click Button / Click Link
  • 原文地址:https://www.cnblogs.com/DOLFAMINGO/p/7538709.html
Copyright © 2020-2023  润新知