caioj1462
【题意】
给出26个字母所代表的权值和一个字符串,要求把字符串分成两段(每一段长度至少为1,也就是必须要有字符),假如这一段子串是一个回文串,那么加上该串所有字符权值之和,求最大的权值和。
【输入格式】
输入一个整数T,表示数据组数
每组数据第一行输入26个数,表示26个字母的权值,第二行输入一个字符串(保证字符串内全是小写字母,2<=字符串长度<=500000)
【输出格式】
输出每组数据的最大权值和
【样例输入】
2
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
aba
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
acacac
【样例输出】
1
6
思路
设顺序的字符串为 A A A,倒序的字符串为 B B B,
题意就是从某个地方断开来嘛。
当前位置为 i i i,在 i i i与 i + 1 i+1 i+1断开,
这时需要判断 A [ 1 ∼ i ] = B [ n − i + 1 ∼ n ] , A [ i + 1 ∼ n ] = B [ 1 ∼ n − i ] A[1\sim i]=B[n-i+1\sim n ],A[i+1\sim n]=B[1\sim n-i] A[1∼i]=B[n−i+1∼n],A[i+1∼n]=B[1∼n−i],转化成求例题就好了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int N=5e5+10;
char a[N],b[N];int ext1[N],ext2[N],nxt[N],n,val[150],ans,sum[N];
void exkmp(char *a,char *b,int *extend)
{
int x=1;nxt[1]=n;
while(x<n&&a[x]==a[x+1])++x;
nxt[2]=x-1;int k=2;
for(int i=3;i<=n;i++)
{
int ed=k+nxt[k]-i,L=nxt[i-k+1];
if(L<ed)nxt[i]=L;
else
{
x=ed<0?0:ed;
while(x+i<=n&&a[x+1]==a[x+i])++x;
nxt[i]=x;k=i;
}
}
x=1;
while(x<=n&&b[x]==a[x])++x;
extend[1]=x-1;k=1;
for(int i=2;i<=n;i++)
{
int ed=k+extend[k]-i,L=nxt[i-k+1];
if(L<ed)extend[i]=L;
else
{
x=ed<0?0:ed;
while(x+i<=n&&a[x+1]==b[x+i])++x;
extend[i]=x;k=i;
}
}
}
int main()
{
int T;scanf("%d",&T);
while(T--)
{
ans=0;
for(int i='a';i<='z';i++)scanf("%d",&val[i]);
scanf("%s",a+1);n=strlen(a+1);int m=n;
sum[0]=0;
for(int i=1;i<=n;i++)b[m--]=a[i],sum[i]=sum[i-1]+val[a[i]];
exkmp(a,b,ext1),exkmp(b,a,ext2);
int tmp=0;
for(int i=1;i<n;i++)
{
ext1[n-i+1]==i?tmp=sum[i]:tmp=0;
ext2[i+1]==n-i?tmp+=sum[n]-sum[i]:0;
ans=max(ans,tmp);
}
printf("%d\n",ans);
}
return 0;
}