题目链接: 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;
}