1. 程式人生 > >HDU 3613 Best Reward(擴展KMP求前後綴回文串)

HDU 3613 Best Reward(擴展KMP求前後綴回文串)

ref gpo namespace .cn pan spa pos tdi kmp

題目鏈接: http://acm.hdu.edu.cn/showproblem.php?pid=3613

題目大意:

大意就是將字符串s分成兩部分子串,
若子串是回文串則需計算價值,否則價值為0,求分割字符串s能獲得的最大價值。

解題思路:將原串s反轉得到rs,然後進行rs,s擴展KMP匹配,得到extend,對於s1的前i個字符如果和s2的後i個字符相等即extend[len-i] == i則前i個字符為回文串;

同理,判斷後len-i個字符是否是回文串用s,rs進行擴展KMP再生成一個extend即可。

代碼

 1 #include<iostream>
 2 #include<cstdio>
 3
#include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int N=1e6+5; 7 const int INF=0x3f3f3f3f; 8 9 int nxt[N],extend1[N],extend2[N],val[N],sum[N]; 10 char s[N],rs[N]; 11 12 void getnext(char *t){ 13 int a,p,len; 14 len=strlen(t); 15 nxt[0]=len;
16 for(int i=1,j=-1;i<len;i++,j--){ 17 if(j<0||i+nxt[i-a]>=p){ 18 if(j<0) 19 p=i,j=0; 20 while(p<len&&t[p]==t[j]) 21 p++,j++; 22 nxt[i]=j; 23 a=i; 24 } 25 else 26 nxt[i]=nxt[i-a];
27 } 28 } 29 30 void ex_kmp(char *s,char *t,int *extend){ 31 int a,p,len1,len2; 32 len1=strlen(s); 33 len2=strlen(t); 34 for(int i=0,j=-1;i<len1;i++,j--){ 35 if(j<0||i+nxt[i-a]>=p){ 36 if(j<0) 37 p=i,j=0; 38 while(p<len1&&j<len2&&s[p]==t[j]) 39 p++,j++; 40 extend[i]=j; 41 a=i; 42 } 43 else extend[i]=nxt[i-a]; 44 } 45 } 46 47 int main(){ 48 int t; 49 scanf("%d",&t); 50 while(t--){ 51 for(int i=0;i<26;i++){ 52 scanf("%d",&val[i]); 53 } 54 scanf("%s",s); 55 int len=strlen(s); 56 for(int i=0;i<len;i++){ 57 rs[len-i-1]=s[i]; 58 } 59 getnext(rs); 60 ex_kmp(s,rs,extend1); 61 getnext(s); 62 ex_kmp(rs,s,extend2); 63 for(int i=0;i<len;i++){ 64 sum[i]=val[s[i]-a]; 65 if(i!=0) 66 sum[i]+=sum[i-1]; 67 } 68 int ans=-INF; 69 //枚舉分割位置(把s[i]歸給前面的子串) 70 for(int i=0;i<len-1;i++){ 71 int tmp=0; 72 if(extend2[len-i]==i) tmp+=sum[i]; 73 i++; 74 if(extend1[i]==len-i) tmp+=sum[len-1]-sum[i-1]; 75 ans=max(ans,tmp); 76 } 77 printf("%d\n",ans); 78 } 79 return 0; 80 }

HDU 3613 Best Reward(擴展KMP求前後綴回文串)