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
题目大意:
字母表的26个字母都有一个价值,给你一个字符串,将该字符串切成两份,对于每一份,如果是回文串,就获得该子串的字母价值
之和,否则该子串的价值为0。求出将字符串切成两份后能够获得的最大价值。
想法:先用Manacher算法求出以每个字母为中心的回文串的长度,并计算该字符串的前缀价值和。然后枚举切割点,得到两份
子串。这样就可以知道每个子串的中心点,然后检查以该子串的中心点作为中心点的回文串的长度,如果长度等于该子串的长度,
那么就加上该子串的价值。然后和最优价值比较就行了。
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=5e5+5;
char s[maxn],t[maxn<<1];
int p[maxn<<1];
int a[maxn],v[26];
void manacher()
{
int len=strlen(s),l=0;
t[l++]='$';
t[l++]='#';
for(int i=0;i<len;++i)
{
t[l++]=s[i];
t[l++]='#';
}
t[l]=0;
int maxx=0,num=0;
for(int i=0;i<l;++i)
{
p[i]=maxx>i?min(p[2*num-i],maxx-i):1;
while(t[i+p[i]]==t[i-p[i]])p[i]++;
if(i+p[i]>maxx)
{
maxx=i+p[i];
num=i;
}
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
for(int i=0;i<26;++i)
scanf("%d",&v[i]);
scanf("%s",s);
int l=strlen(s);
a[0]=v[s[0]-'a'];
for(int i=1;i<l;++i)
{
a[i]=a[i-1]+v[s[i]-'a'];
}
manacher();
int ans=0;
for(int i=0;i<l-1;++i)
{
int tmp=0;
int num=p[i+2]-1;
if(num==i+1)//前缀是不是回文
tmp+=a[i];
num=p[i+l+2]-1;
if(num==l-i-1)//后缀是不是回文
tmp+=a[l-1]-a[i];
if(tmp>ans)
ans=tmp;
}
printf("%dn",ans);
}
return 0;
}
本文发布于:2024-01-28 16:17:46,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/17064298698671.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |