HDU 3613 Best Reward(扩展kmp)

来源:互联网 发布:mac怎么转换音频格式 编辑:程序博客网 时间:2024/04/30 04:27

Description
给出一个只由小写字母组成的字符串以及每个小写字母的价值,现要将这个字符串分成两半,如果某一半是回文串则将累加这一半串的价值(价值即为这个串中每个字符的价值之和),问能得到的最大价值
Input
第一行为一整数T表示用例组数,每组用例首先输入26个整数表示a到z这26个小写字母的价值,之后输入长度不超过500000的一个字符串
Output
对于每组用例,输出将该字符串分成两半后能得到的最大价值
Sample Input
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
Sample Output
1
6
Solution
问题在于如果快速判断a串的前缀和后缀是否是回文串,这里只说前缀(因为后缀就是反串的前缀),考虑串a与其反串b的匹配,如果a的某个前缀是回文串,那么因为其反串是b串的一个后缀,所以只要extend[i]=len-i,那么前缀a[0~i]就是一个回文串,同理,在b与a的匹配中,如果extend[i]=len-i,那么后缀a[len-1-i,len-1]就是一个回文串,做两边扩展kmp通过extend数组可以得到以第i个字符结尾或者开始的前后缀是否为回文串,之后O(n)枚举切割点更新最大价值即可(需要预处理出价值前缀和)
Code

#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>using namespace std;#define maxn 555555char a[maxn],b[maxn];int T,v[33],sum[maxn],flag1[maxn],flag2[maxn],nex[maxn],extend[maxn];void extend_kmp(char *a,char *b) {    int i,j,k,la=strlen(a),lb=strlen(b);    for(i=0;i+1<la&&a[i+1]==a[i];i++);    nex[1]=i;    k=1;    for(i=2;i<la;i++)     {        int len=k+nex[k];        nex[i]=min(nex[i-k],max(0,len-i));        while(i+nex[i]<la&&a[nex[i]]==a[i+nex[i]])nex[i]++;        if(i+nex[i]>k+nex[k])k=i;    }    for(i=0;i<la&&i<lb&&a[i]==b[i];i++);    extend[0]=i;    k=0;    for(i=1;i<lb;i++)     {        int len=k+extend[k];        extend[i]=min(nex[i-k],max(0,len-i));        while(i+extend[i]<la&&i+extend[i]<lb&&a[extend[i]]==b[extend[i]+i])            extend[i]++;        if(k+extend[k]<i+extend[i])k=i;    }}int main(){       scanf("%d",&T);    while(T--)    {        memset(flag1,0,sizeof(flag1));        memset(flag2,0,sizeof(flag2));        for(int i=0;i<26;i++)scanf("%d",&v[i]);        scanf("%s",a);        int len=strlen(a);        for(int i=0;i<len;i++)b[i]=a[len-1-i];        sum[0]=v[a[0]-'a'];        for(int i=0;i<len;i++)sum[i]=sum[i-1]+v[a[i]-'a'];        extend_kmp(a,b);        for(int i=0;i<len;i++)if(extend[i]==len-i)flag1[len-1-i]=1;        extend_kmp(b,a);        for(int i=0;i<len;i++)if(extend[i]==len-i)flag2[i]=1;        int ans=v[a[0]-'a'];        for(int i=0;i<len-1;i++)        {            int temp=flag1[i]*sum[i]+flag2[i+1]*(sum[len-1]-sum[i]);            ans=max(ans,temp);        }        printf("%d\n",ans);    }    return 0;}
0 0
原创粉丝点击