Best Reward HDU - 3613(manacher)

Best Reward

 HDU - 3613

题意:每个小写字母对应有一个价值,给一个小写字母组成的串s,现在要把s切割成两段,如果切割后的串是回文串,那么价值就是该段所有字母的价值之和,问总价值最大多少。

用manacher找到前缀回文和后缀回文,枚举切点更新最大之即可。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int inf=0x3f3f3f3f;
 4 const int maxn=500000+10;
 5 char s[maxn<<1];
 6 int r[maxn<<1],sum[maxn],val[27];
 7 int per[maxn],pos[maxn];//per标记前i个字符为回文串,pos标记后i个字符为回文串
 8 
 9 int main(){
10     int T;
11     scanf("%d",&T);
12     while(T--){
13         for(int i=0;i<26;++i)scanf("%d",&val[i]);
14         scanf("%s",s);
15         int len=strlen(s);
16         sum[0]=val[s[0]-'a'];
17         for(int i=1;i<len;++i) sum[i]=sum[i-1]+val[s[i]-'a'];
18         for(int i=len;i>=0;--i){
19             s[i+i+2]=s[i];
20             s[i+i+1]='#';
21         }
22         s[0]='*';
23         int id=0;
24         for(int i=2;i<len+len+1;++i){
25             if(r[id]+id>i) r[i]=min(r[2*id-i],r[id]+id-i);
26             else r[i]=1;
27             while(s[i-r[i]] == s[i+r[i]]) ++r[i];
28             if(id+r[id]<i+r[i]) id=i;
29             if(i-r[i]==0) per[r[i]-1]=T+1;//表示前缀(前r[i]-1个字符)是回文串
30             if(i+r[i]==len+len+2) pos[r[i]-1]=T+1;//表示后缀(后r[i]-1个字符)是回文串
31         }
32         int ans=0;
33         for(int i=1;i<len;++i){
34             int temp=0;
35             if(per[i]==T+1) temp+=sum[i-1];
36             if(pos[len-i]==T+1) temp+=sum[len-1]-sum[i-1];
37             ans=max(ans,temp);
38         }
39         printf("%d\n",ans);
40     }
41     return 0;
42 }
View Code

 

另解:扩展KMP

 

posted @ 2017-08-22 11:56  yijiull  阅读(175)  评论(0编辑  收藏  举报