题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3613
题目大意:
题目大意就是将字符串s分成两部分子串,
若子串是回文串则需计算价值,否则价值为0,求分割字符串s能获得的最大价值。
解题思路:
用manacher算法计算出p[i],每次计算p[i]是顺便计算一下这段回文串
是否能到达边界,若能则计算出前缀或者后缀的结束位置,标记起来。//还有之前数组开1e6+5教C++是错的,改成2e6+5就对了,不觉明历。。。。
代码
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int N=2e6+5; 7 const int INF=0x3f3f3f3f; 8 9 int len1,len2; 10 int p[N],sum[N],val[N],pre[N],hou[N]; 11 char s[N],str[N]; 12 13 void init(){ 14 str[0]=‘$‘; 15 str[1]=‘#‘; 16 for(int i=0;i<len1;i++){ 17 str[i*2+2]=s[i]; 18 str[i*2+3]=‘#‘; 19 } 20 len2=len1*2+2; 21 str[len2]=‘\0‘; 22 } 23 24 void manacher(){ 25 int id=0,mx=0; 26 for(int i=1;i<len2;i++){ 27 if(mx>i) p[i]=min(p[2*id-i],mx-i); 28 else p[i]=1; 29 while(str[i+p[i]]==str[i-p[i]]) 30 p[i]++; 31 if(p[i]+i>mx){ 32 id=i; 33 mx=p[i]+i; 34 } 35 if(i-p[i]==0){ 36 pre[p[i]+i-1]=1; 37 } 38 if(i+p[i]==len2){ 39 hou[i-p[i]+1]=1; 40 } 41 } 42 } 43 44 45 int main(){ 46 int t; 47 scanf("%d",&t); 48 while(t--){ 49 memset(pre,0,sizeof(pre)); 50 memset(hou,0,sizeof(hou)); 51 for(int i=0;i<26;i++){ 52 scanf("%d",&val[i]); 53 } 54 scanf("%s",s); 55 len1=strlen(s); 56 init(); 57 manacher(); 58 for(int i=1;i<len2;i++){ 59 if(i==‘#‘) sum[i]=sum[i-1]; 60 else sum[i]=sum[i-1]+val[str[i]-‘a‘]; 61 } 62 int ans=-INF; 63 //枚举分割点 64 for(int i=2;i<len2-1;i++){ 65 int tmp=0; 66 if(pre[i]) tmp+=sum[i]; 67 if(hou[i]) tmp+=sum[len2-1]-sum[i]; 68 ans=max(ans,tmp); 69 } 70 printf("%d\n",ans); 71 } 72 return 0; 73 }