HDU 3613 Best Reward(扩展KMP求前后缀回文串)

时间:2021-05-14 03:28:28

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3613

题目大意:

大意就是将字符串s分成两部分子串,
若子串是回文串则需计算价值,否则价值为0,求分割字符串s能获得的最大价值。

解题思路:将原串s反转得到rs,然后进行rs,s扩展KMP匹配,得到extend,对于s1的前i个字符如果和s2的后i个字符相等即extend[len-i] == i则前i个字符为回文串;

同理,判断后len-i个字符是否是回文串用s,rs进行扩展KMP再生成一个extend即可。

代码

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e6+;
const int INF=0x3f3f3f3f; int nxt[N],extend1[N],extend2[N],val[N],sum[N];
char s[N],rs[N]; void getnext(char *t){
int a,p,len;
len=strlen(t);
nxt[]=len;
for(int i=,j=-;i<len;i++,j--){
if(j<||i+nxt[i-a]>=p){
if(j<)
p=i,j=;
while(p<len&&t[p]==t[j])
p++,j++;
nxt[i]=j;
a=i;
}
else
nxt[i]=nxt[i-a];
}
} void ex_kmp(char *s,char *t,int *extend){
int a,p,len1,len2;
len1=strlen(s);
len2=strlen(t);
for(int i=,j=-;i<len1;i++,j--){
if(j<||i+nxt[i-a]>=p){
if(j<)
p=i,j=;
while(p<len1&&j<len2&&s[p]==t[j])
p++,j++;
extend[i]=j;
a=i;
}
else extend[i]=nxt[i-a];
}
} int main(){
int t;
scanf("%d",&t);
while(t--){
for(int i=;i<;i++){
scanf("%d",&val[i]);
}
scanf("%s",s);
int len=strlen(s);
for(int i=;i<len;i++){
rs[len-i-]=s[i];
}
getnext(rs);
ex_kmp(s,rs,extend1);
getnext(s);
ex_kmp(rs,s,extend2);
for(int i=;i<len;i++){
sum[i]=val[s[i]-'a'];
if(i!=)
sum[i]+=sum[i-];
}
int ans=-INF;
//枚举分割位置(把s[i]归给前面的子串)
for(int i=;i<len-;i++){
int tmp=;
if(extend2[len-i]==i) tmp+=sum[i];
i++;
if(extend1[i]==len-i) tmp+=sum[len-]-sum[i-];
ans=max(ans,tmp);
}
printf("%d\n",ans);
}
return ;
}