bx回文


Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 0    Accepted Submission(s): 0


Problem Description


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

每次操作可以删掉一个长度为k(1 <= k <= n)的连续回文子串,bx获得 ak的愉悦值。

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

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

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


Input


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

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

第二行n个整数,第i个表示 ai。

第三行为字符串S。

1 <= T <= 20
1 <= n <= |S| < 5000 
0 <=  ai < 1000000000 
S只包括小写字母。



Output


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


Sample Input


2
3
1 2 3
aba
3
3 2 1
aba


 



Sample Output


3 9


 


【分析】

乍一看以为很复杂的dp....然而...考虑一下预处理n^2

vis[i][j]表示[i,j]这一段是否为回文

所以f[i]=max(f[j]+a[i-j+1])(vis[i][j]==1)  0<=j<=i  

//这里注意一个坑点,需要判断(i-j+1<=n),第一次计算不会有问题,因为a数组默认为0,但是多组数据时,先出现n=100的数据,再计算n=10的数据就有可能出错,当然每次memeset(a)也没有问题

【代码】


#include <cstdio>
#include <algorithm>
#include <cstring>
#include <algorithm>
using namespace std;

long long a[6000];
long long f[6000];
char s[6000];
int vis[5010][5010];
int main()
{
int pp;scanf("%d",&pp);
while (pp--)
{
int n;scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
scanf("%s",s);
int len=strlen(s);
memset(vis,0,sizeof(vis));
for (int i=0;i<len;i++)
{
int l=0;
while (i-l>=0&&i+l<len&&s[i-l]==s[i+l]) vis[i-l][i+l]=1,l++;
l=1;
while (i-l+1>=0&&i+l<len&&s[i-l+1]==s[i+l]) vis[i-l+1][i+l]=1,l++;
}
memset(f,0,sizeof(f));
for (int i=0;i<len;i++)
for (int j=i;j>=0;j--)
if (vis[j][i]&&i-j+1<=n)
if (j==0)
f[i]=max(f[i],a[i-j+1]);
else
f[i]=max(f[i],f[j-1]+a[i-j+1]);
// for (int i=0;i<len;i++) printf("%lld ",f[i]);
printf("%lld\n",f[len-1]);
}
return 0;
}