hdu 3613"Best Reward"(Manacher算法)
题意:
国王为了犒劳立下战功的大将军Li,决定奖给Li一串项链,这个项链一共包含26中珠子"a~z",每种珠子都有
相应的价值(-100~100),当某个项链可以构成回文时,那么这个项链的价值就是每个珠子价值的加和,如果
构不成,那么这个项链的价值就为0;
求如何将国王奖赏的一串项链拆成价值加和最大的两串项链,求出这个最大价值。
题解:
本来我是在找有关拓展KMP的相关题目的,百度到一大牛的博客(“扩展KMP题目”),当做到第二个题目的时候,
思来想去,就是没找到其和拓展KMP的联系,然后,感觉可以用Manacher算法,刷刷刷撸了个Manacher的代码
提交,AC,所以,我暂且谈谈如何用Manacher算法解这道题;
①首先将项链串s[]预处理(了解Manacher算法就理解啥意思了);
②准备一个数组sum[],sum[ i ]:预处理后的数组中前 i 个字符对应的价值的加和,'#'当作0;
③使用Manacher算法求解出回文半径数组radius[];
④假设从 i 位置切割项链,将项链分成[ 0,i ],[ i,len-1 ]两串,分别求解对应的总价值,令ans=max{从i位置分割的总价值}
AC代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 #define INF 0x3f3f3f3f 6 #define lowbit(x) (x&-x) 7 #define mem(a,b) memset(a,b,sizeof(a)) 8 const int maxn=5e5+50; 9 10 int val[26]; 11 char s[2*maxn]; 12 char temp[maxn]; 13 int radius[2*maxn]; 14 int sum[2*maxn]; 15 void Trans() 16 { 17 int len=strlen(s); 18 strcpy(temp,s); 19 for(int i=0;i < len;++i) 20 { 21 s[2*i]='#'; 22 s[2*i+1]=temp[i]; 23 } 24 s[2*len]='#'; 25 s[2*len+1]='\0'; 26 } 27 void Manacher() 28 { 29 mem(radius,0); 30 int len=strlen(s); 31 int R=0; 32 int K=0; 33 radius[0]=0; 34 for(int i=1;i < len;++i) 35 { 36 int cnt=0; 37 if(i >= R) 38 { 39 while(i+cnt < len && i-cnt >= 0 && s[i+cnt] == s[i-cnt]) 40 cnt++; 41 radius[i]=cnt; 42 if(i+cnt-1 > R) 43 { 44 R=i+cnt-1; 45 K=i; 46 } 47 } 48 else 49 { 50 int j=K-(i-K); 51 if(i+radius[j]-1 != R) 52 radius[i]=min(R-i+1,radius[j]); 53 else 54 { 55 cnt=R-i+1; 56 while(i-cnt >= 0 && i+cnt < len && s[i-cnt] == s[i+cnt]) 57 cnt++; 58 radius[i]=cnt; 59 if(i+cnt-1 > R) 60 { 61 R=i+cnt-1; 62 K=i; 63 } 64 } 65 } 66 } 67 } 68 int Solve() 69 { 70 Trans();//预处理字符串s 71 Manacher(); 72 73 int len=strlen(s); 74 sum[0]=0; 75 for(int i=1;i < len;++i)//前缀和 76 sum[i]=sum[i-1]+(s[i] == '#' ? 0:val[s[i]-'a']); 77 78 79 int ans=-INF; 80 for(int i=1;i < len-2;i+=2) 81 { 82 int cnt=0; 83 int x=(i+1)>>1;//[0,i+1]的中点坐标 84 if(radius[x] == x+1)//判断[0,i]是否构成回文子串 85 cnt += sum[i]; 86 87 int y=(len+i)>>1;//[i+1,len-1]的中点坐标 88 if(radius[y] == len-y)//判断[i+1,len-1]是否构成回文子串 89 cnt += sum[len-1]-sum[i]; 90 ans=max(ans,cnt); 91 } 92 return ans; 93 } 94 int main() 95 { 96 // freopen("C:/Users/hyacinthLJP/Desktop/stdin/contest","r",stdin); 97 int test; 98 scanf("%d",&test); 99 while(test--) 100 { 101 for(int i=0;i < 26;++i) 102 scanf("%d",val+i); 103 scanf("%s",s); 104 printf("%d\n",Solve()); 105 } 106 return 0; 107 }