HDU 3613 Manacher

来源:互联网 发布:蓝果网络 编辑:程序博客网 时间:2024/05/17 22:45

26个字母都有一个价值,给你一个字符串,将该字符串切成两份,对于每一份,如果是回文串,就获得该子串的字母价值之和,否则该子串的价值为0。求出将字符串切成两份后能够获得的最大价值。

用Manacher算法求出以每个字母为中心的回文串的长度,枚举切割点


#include <bits/stdc++.h>using namespace std;const int MAXN=550000;char Ma[MAXN*2];int Mp[MAXN*2];void Manacher(char s[],int len){    int l=0;    Ma[l++]='$';    Ma[l++]='#';    for(int i=0;i<len;i++){        Ma[l++]=s[i];        Ma[l++]='#';    }    Ma[l]=0;    int mx=0,id=0;    for(int i=0;i<l;i++){        Mp[i]=mx>i?min(Mp[2*id-i],mx-i):1;        while(Ma[i+Mp[i]]==Ma[i-Mp[i]]) Mp[i]++;        if(i+Mp[i]>mx){            mx=i+Mp[i];            id=i;        }    }}char s[MAXN];int sum[MAXN*2];int v[30];void input(){    for(int i=1;i<=26;i++)    scanf("%d",&v[i]);    scanf("%s",s);}void get_sum(){    int len=strlen(Ma);    for(int i=1;i<len;i++)    {        sum[i]=sum[i-1];        if('a'<=Ma[i]&&Ma[i]<='z')        sum[i]+=v[Ma[i]-'a'+1];  //   printf("%d %d\n",i,sum[i]);    }}void solve(){    int len=strlen(s);    Manacher(s,len);    get_sum();    len=strlen(Ma);    int ans=-0x3f3f3f3f;    for(int i=3;i<len-1;i=i+2)    {        int a1=0,a2=0;        if((((2+(i-1))/2)+Mp[(2+(i-1))/2]-1)>=(i-1))        a1=sum[i]-sum[1];        if(((len+i-1)/2-Mp[(len+i-1)/2]+1)<=(i+1))        a2=sum[len-2]-sum[i];        if(ans<a1+a2)        ans=a1+a2;    }    cout<<ans<<endl;}int main(){    int T;    cin>>T;    while(T--)    {        input();        solve();    }}


原创粉丝点击