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

来源:互联网 发布:it职业技术学校 编辑:程序博客网 时间:2024/04/28 21:56

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


题解:

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]);


代码如下:

#include <bits/stdc++.h>using namespace std;#define ms(a, b)  memset((a), (b), sizeof(a))typedef long long LL;const int INF = 2e9;const LL LNF = 9e18;const int mod = 1e9+7;const int maxn = 5000+10;char s[maxn];LL a[maxn], dp[maxn];bool ok[maxn][maxn];int n, len;void init(){    ms(ok,0);    ms(dp,0);    for(int i = 1; i<=len; i++)    {        int l = i, r = i;        while(l>=1 && r<=len && (r-l+1)<=n && s[l]==s[r])            ok[l--][r++] = 1;    }    for(int i = 1; i<=len; i++)    {        int l = i, r = i+1;        while(l>=1 && r<=len && (r-l+1)<=n && s[l]==s[r])            ok[l--][r++] = 1;    }}void solve(){    for(int i = 1; i<=len; i++)    for(int j = 1; j<=i; j++)    {        if(ok[j][i])            dp[i] = max(dp[i],dp[j-1]+a[i-j+1]);    }    printf("%lld\n",dp[len]);}int main(){    int T;    scanf("%d",&T);    while(T--)    {        scanf("%d",&n);        for(int i = 1; i<=n; i++)            scanf("%lld",&a[i]);        scanf("%s", s+1);        len = strlen(s+1);        init();        solve();    }    return 0;}


0 0
原创粉丝点击