题目大意:小写字母组成的长n的串, 每种字母有一定的价值(可以为负), 要你分成切成两个串, 总价值为两个串价值和, 若是回文, 则串的价值为每个字母价值和, 否则为0。 问最大价值多少。
思路:通过kmp和分别求出前缀回文和后缀回文,然后遍历一遍长度的解!
#include"cstdio"
#include"cmath"
#include"cstring"
#include"cstdlib"
#include"iostream"
#include"algorithm"
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
char s1[500004],s2[500004];
int next[500004],p1[500004],p2[500004],sum[500005];
void getnext(char *t)
{
int i,j;
i=0;
j=-1;
next[0]=-1;
while(t[i])
{
if(t[i]==t[j]||j==-1) next[++i]=++j;
else j=next[j];
}
}
int kmp(char *s,char *t)
{
int i,j;
i=j=0;
int len =strlen(t);
getnext(t);
while(i<len&&j<len)
{
if(j==-1||s[i]==t[j])
{
i++;
j++;
}
else j=next[j];
}
return j;
}
int main()
{
int t;
cin>>t;
while(t--)
{
int i;
int v[123];
memset(p1,0,sizeof(p1));
memset(p2,0,sizeof(p2));
memset(sum,0,sizeof(sum));
for(i=0; i<26; i++) cin>>v[i];
scanf("%s",s1);
int len=strlen(s1);
for(i=0; s1[i]; i++)
{
sum[i+1]=sum[i]+v[s1[i]-'a'];
s2[len-i-1]=s1[i]; //将原串反转
}
s2[len]='\0';
int k;
k=kmp(s2,s1); //把反转串当S串,原串作为T串。
while(k) // kmp之后,根据性质可以得出从k开始k=next[k]转换下去的所有位置都是能构成回文的位置。
{
p1[k]=1;
k=next[k];
}
k=kmp(s1,s2);
while(k) //同理求后缀回文
{
p2[k]=1;
k=next[k];
}
int max=-999999999;
for(i=1; i<len; i++)
{
int tep=0;
if(p1[i]==1) tep+=sum[i]; //分割前面是回文的话
if(p2[len-i]==1) tep+=sum[len]-sum[i];//后面是回文的话
if(tep>max) max=tep;
}
cout<<max<<endl;
}
}