扩展kmp求最长回文子串_hdu3613 Best Reward 扩展kmp or O(n)求最大回文子串

/**

题目:hdu3613 Best Reward

链接:http://acm.hdu.edu.cn/showproblem.php?pid=3613题意:有一个字符串,把他切成两部分。

如果这部分是回文串,那么他的值为所有字母的权值和。否则这部分值为0;这两部分的值和为该切法的权值。

求最大的切法的权值。

思路:

如果能够判断[0,i],[i,n-1]是一个回文串(0<=i

取最大的。

扩展kmp的做法。

先计算l[i]=1,表示[0,i]是一个回文串;那么[0,k1]与[k2,i]相等。0是固定的。

获得原串t的反转串s。求extend[i],表示s串从[i,n-1]与原串t的最长公共前缀。

枚举s串的i。那么从[i,n-1]的长度n-i;如果extend[i]*2+1>=n-i那么表示原串t中的[0,n-1-i]是一个回文串即l[n-1-i] = 1;

现在求r[i]=1,表示[i,n-1]是一个回文串;那么[i,k1]与[k2,n-1]相等。n-1是固定的。

求extend[i],表示t串从[i,n-1]与s串的最长公共前缀。

枚举t串的i。那么从[i,n-1]的长度为n-i;如果extend[i]*2+1>=n-i那么表示原串[i,n-1]是一个回文串即r[i] = 1;*/#include#include#include#include#include#include

using namespacestd;const int INF = 0x3f3f3f3f;const int maxn = 5e5+10;chars[maxn], t[maxn];intf[maxn], Next[maxn], extend[maxn];int sum[maxn], w[30];int l[maxn], r[maxn];///l[i]=1表示[0,i]是一个回文串.r[i]=1表示[i,n-1]是一个回文串。

void GetNext(char *T,int*next)

{int a=0;int Tlen=strlen(T);

next[0]=Tlen;while(a

next[1]=a;

a=1;for(int k=2;k

{int p=a+next[a]-1,L=next[k-a];if((k-1)+L>=p)

{int j=(p-k+1)>0? p-k+1:0;while(k+j

next[k]=j;

a=k;

}else next[k]=L;

}

}void GetExtend(char *S,char *T,int* next,int*extend)

{int a=0;

GetNext(T,next);int Slen=strlen(S);int Tlen=strlen(T);int MinLen=Slen

extend[0]=a;

a=0;for(int k=1;k

{int p=a+extend[a]-1,L=next[k-a];if((k-1)+L>=p)

{int j=(p-k+1)>0? p-k+1:0;while(k+j

extend[k]=j;

a=k;

}else extend[k]=L;

}

}void getlr(int* extend,int *l,int flag,intn)

{intlen;for(int i = 0; i < n; i++){

len= n-i;if(extend[i]*2+1>=len){if(flag) l[i] = 1;else l[n-1-i] = 1;

}

}

}void test(int *f,intn)

{for(int i = 0; i < n; i++){

printf("f[%d] = %d\n",i,f[i]);

}

}intmain()

{//freopen("in.txt","r",stdin);

intT;

cin>>T;while(T--){for(int i = 0; i < 26; i++) scanf("%d",&w[i]);

scanf("%s",t);int n =strlen(t);for(int i = 0; i < n; i++) s[n-1-i] =t[i];

s[n]= '\0';

sum[0] = w[t[0]-'a'];for(int i = 1; i < n; i++){

sum[i]= sum[i-1]+w[t[i]-'a'];

}

memset(l,0, sizeofl);

memset(r,0, sizeofr);

GetExtend(s,t,Next,extend);

getlr(extend,l,0,n);

GetExtend(t,s,Next,extend);

getlr(extend,r,1,n);int ans = -INF, ansa, ansb;for(int i = 1; i < n; i++){if(l[i-1]){

ansa= sum[i-1];

}else ansa = 0;if(r[i]){

ansb= sum[n-1]-sum[i-1];

}else ansb = 0;

ans= max(ans,ansa+ansb);

}

printf("%d\n",ans);

}return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值