hdu 3613 Manacher+枚举+前缀和打表

点击打开链接
//马拉车算法+枚举切割点+打表储存(前缀和)
//manacher算法求最长回文子串,时间复杂度为O(n),基本思想是充分利用已求得的回文串长度
//关键是构造P数组
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=5*1e5+10;
int P[maxn<<1];
char T1[maxn];
char T2[maxn<<1];
int sum[maxn];
int num[30];
//P[i]-1恰好是位置i处的最长回文子串长度
//求解P数组
void Manacher(char T[])
{
        int pos=0,mx=0;             //mx为当前可以触及的最远位置,pos为这种状态时的对称轴位置
        P[0]=0;                 //0位置不考虑,为$标志
        for(int i=1;T[i];i++)
        {
            if(mx>i) P[i]=min(P[2*pos-i],mx-i);         //第一种情况:i在mx左侧,在左侧时又有两种情况:
            //两种情况:1.i关于pos的j的回文串较短 2.i关于pos的j的回文串较长,分别对应min中的两个值
            else P[i]=1;                    //i在mx右侧的情况
            while(T[i+P[i]]==T[i-P[i]]) P[i]++;                 //进行匹配
            if(mx<P[i]+i)                   //更新mx值和pos值
            {
                mx=P[i]+i;
                pos=i;
            }
        }
}
void getsum()
{
    sum[0]=num[T1[0]-'a'];
    int f=strlen(T1);
    for(int i=1;i<f;i++)
        sum[i]=sum[i-1]+num[T1[i]-'a'];
}
// 构造T2串
//解决长度奇偶性带来的对称轴位置问题:在所有的空隙位置(包括首尾)插入一种原串中没有的符号,这样,奇数加偶数必为奇数
void init()
{
    scanf("%s",T1);
    int i,j=2;
    T2[0]='$',T2[1]='#';                //$符号是为了防止数组下标越界
    for(i=0;T1[i];i++)
    {
        T2[j++]=T1[i];
        T2[j++]='#';
    }
    T2[j]='\0';
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(sum,0,sizeof(sum));
        memset(num,0,sizeof(num));
        int mi=0;
        for(int i=0;i<26;i++)
              scanf("%d",&num[i]);
        init();
        getsum();
        Manacher(T2);
        //枚举切割点
        int f=strlen(T1);
        for(int i=0;i<f-1;i++)
        {
            //先左串,后右串
            int temp=0;
            int k1=i+1,k2=f-i-1;
            int k=P[i+2]-1;
            if(k==k1) temp+=sum[i];
            k=P[i+f+2]-1;
            if(k==k2) temp+=sum[f-1]-sum[i];
            mi=max(mi,temp);
         }
    printf("%d\n",mi);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值