题目: http://acm.hdu.edu.cn/showproblem.php?pid=3613
题意:
给定一个字符串s;
每个字符有一个权值;
砍成两段,若某段为回文串则其价值为各字符的价值和,非回文串则价值为0;
问两段的价值和最大是多少。
分析:
法一:
做完Manacher,枚举砍点就是了。
法二:
设给定字符串为s,将其反转后为t;
以s为文本串,t为模板串跑exKMP,得到extend数组exS;
以t为文本串,s为模板串跑exKMP,得到extend数组exT;
然后枚举砍点i,根据exS[i]判断第二段是否回文,根据exT[len-i]判断第一段是否回文。
代码:
法一:Manacher
#include <bits/stdc++.h>
using namespace std;
typedef long long llong;
const int tmax=500005;
int val[30],p[tmax*2],sum[tmax*2];
char s[tmax*2],a[tmax];
int id,len;
void work()
{
int ans=-500005*100,j,tmp,center;
for(int i=2;i<len/2;i++)
{
tmp=0;j=i+p[i]-1;
if(p[i]==i) tmp=sum[j];
center=j+(len-1-j)/2;
if(p[center]==len-center) tmp+=sum[len-1]-sum[j];
ans=max(ans,tmp);
}
cout<<ans<<endl;
return;
}
int main()
{
int kase,la;
scanf("%d",&kase);
while(kase--)
{
for(int i=0;i<26;i++)
scanf("%d",&val[i]);
scanf("%s",a);
memset(p,0,sizeof(p));
id=len=0;
la=strlen(a);
s[0]='$';
for(int i=0;i<la;i++)
{
s[++len]='#';
s[++len]=a[i];
}
s[++len]='#';
s[++len]='\0';
for(int i=2;i<len;i++)
if(s[i]!='#')
sum[i]=sum[i-1]+val[s[i]-'a'];
else sum[i]=sum[i-1];
for(int i=2;i<len;i++)
{
if(p[id]+id>i) p[i]=min(p[2*id-i],p[id]+id-i);
else p[i]=1;
while(s[i-p[i]]==s[i+p[i]]) p[i]++;
if(id+p[id]<i+p[i]) id=i;
}
work();
}
return 0;
}
法二:exKMP
#include <bits/stdc++.h>
using namespace std;
typedef long long llong;
const int tmax=500005;
int val[30],len,sum[tmax];
int nxtS[tmax],exS[tmax],nxtT[tmax],exT[tmax];
char s[tmax],t[tmax];
void getNext(char *s,int *nxt)
{
int i=0,j,p0;
nxt[0]=len;
while(s[i]==s[i+1]&&i+1<len) i++;
nxt[1]=i;
p0=1;
for(i=2;i<len;i++)
{
if(i+nxt[i-p0]<p0+nxt[p0])
nxt[i]=nxt[i-p0];
else
{
j=nxt[p0]+p0-i;
j=max(j,0);
while(i+j<len&&s[j]==s[i+j]) j++;
nxt[i]=j;
p0=i;
}
}
return;
}
void exKMP(char *s,char *t,int *nxt,int *ex)
{
int i=0,j,p0;
while(s[i]==t[i]&&i<len) i++;
ex[0]=i;
p0=0;
for(i=1;i<len;i++)
{
if(i+nxt[i-p0]<p0+ex[p0])
ex[i]=nxt[i-p0];
else
{
j=ex[p0]+p0-i;
j=max(j,0);
while(i+j<len&&s[i+j]==t[j]) j++;
ex[i]=j;
p0=i;
}
}
return;
}
void work()
{
int ans=-500000*105;
for(int i=1;i<len;i++)
{
int tmp=0;
if(exS[i]==len-i) tmp+=sum[len-1]-sum[i-1];
if(exT[len-i]==i) tmp+=sum[i-1];
ans=max(ans,tmp);
}
cout<<ans<<endl;
return;
}
int main()
{
int kase;
scanf("%d",&kase);
while(kase--)
{
for(int i=0;i<26;i++)
scanf("%d",&val[i]);
scanf("%s",s);
len=strlen(s);
for(int i=0;i<len;i++)
{
t[i]=s[len-i-1];
sum[i]=(i==0?0:sum[i-1])+val[s[i]-'a'];
}
getNext(s,nxtS);
getNext(t,nxtT);
exKMP(s,t,nxtT,exS);
exKMP(t,s,nxtS,exT);
work();
}
return 0;
}