题意:
给出一个字符串,并且给出每种字符串对应的价值,现在要二分这个字符串,如果二分的两部分,如果是回文串就加上对应字符的价值所谓这两个部分的价值,如果不是回文两个部分的价值为0。
题解:
两种方法:
法一:
这题相当于可以转化为求回文前缀和后缀,求回文前缀:将原串反转接到原串后面。求回文后缀:将原串接到原串反转后的串后面。人后求next数组,next[len]就最长的那个回文前缀,不断k=next[k]就能找出前面的回文前缀。
最后只要枚举二分点,求价值最大值。
法二:
用扩展kmp,如果用反转串去匹配原串得到后缀回文,用原串匹配反转串得到前缀回文。
方法一:
#include<iostream> #include<math.h> #include<stdio.h> #include<algorithm> #include<string.h> #include<vector> #include<map> using namespace std; //typedef long long lld; const int oo=0x3f3f3f3f; //const lld OO=1LL<<61; const int MOD=10007; const int maxn=500005; char s1[maxn<<1],s2[maxn<<1]; int next[maxn<<1]; int pre[maxn<<1],suf[maxn<<1]; int sum[maxn],val[30]; void get_next(char ss[],int len) { int i=0;next[i]=-1; int j=-1; while(i<len) { if(j==-1||ss[i]==ss[j]) { i++;j++; next[i]=j; } else j=next[j]; } } void pre_init(int len) { for(int i=0;i<len;i++) { s2[i]=s1[len-i-1]; } s1[len]='#'; s1[len+1]='\0'; s2[len]='\0'; strcat(s1,s2); get_next(s1,2*len+1); int k=2*len+1; memset(pre,0,sizeof pre); while(next[k]) { pre[next[k]]=1; k=next[k]; } } void suf_init(int len) { s2[len]='#'; s2[len+1]='\0'; s1[len]='\0'; strcat(s2,s1); get_next(s2,2*len+1); int k=2*len+1; memset(suf,0,sizeof suf); while(next[k]) { suf[next[k]]=1; k=next[k]; } } int main() { int T; scanf("%d",&T); while(T--) { for(int i=0;i<26;i++) scanf("%d",&val[i]); scanf("%s",s1); int len=strlen(s1); sum[0]=0; for(int i=1;i<=len;i++) sum[i]=sum[i-1]+val[s1[i-1]-'a']; pre_init(len); suf_init(len); int ans=-oo,sm; for(int i=1;i<=len-1;i++) { sm=0; if(pre[i])sm+=sum[i]; if(suf[len-i])sm+=sum[len]-sum[i]; ans=max(ans,sm); } printf("%d\n",ans); } return 0; } /** addfg addfg addad addad */
方法二:
#include<iostream> #include<math.h> #include<stdio.h> #include<algorithm> #include<string.h> #include<vector> #include<map> using namespace std; //typedef long long lld; const int oo=0x3f3f3f3f; //const lld OO=1LL<<61; const int MOD=10007; const int maxn=500005; char s1[maxn],s2[maxn]; int next[maxn],extend[maxn]; int val[30],sum[maxn]; int pre[maxn],suf[maxn]; void get_extend(char T[],int len) { int k=0; next[0]=len; while(k<len-1&&T[k]==T[k+1])k++; next[1]=k; k=1; for(int i=2;i<len;i++) { int p=k+next[k]-1,L=next[i-k]; if(i+L-1>=p) { int j=max(p-i+1,0); while(i+j<len&&T[i+j]==T[j])j++; next[i]=j; k=i; } else next[i]=L; } } void Ekmp(char S[],char T[],int lenS,int lenT) { int k=0; while(k<lenT&&k<lenS&&S[k]==T[k])k++; extend[0]=k; k=0; for(int i=1;i<lenS;i++) { int p=k+extend[k]-1,L=next[i-k]; if(i+L-1>=p) { int j=max(p-i+1,0); while(i+j<lenS&&j<lenT&&S[i+j]==T[j])j++; extend[i]=j; k=i; } else extend[i]=L; } } int main() { int T,L,E,G; scanf("%d",&T); while(T--) { for(int i=0;i<26;i++) scanf("%d",&val[i]); scanf("%s",s1); int len=strlen(s1); sum[0]=0; for(int i=1;i<=len;i++) sum[i]=sum[i-1]+val[s1[i-1]-'a']; for(int i=0;i<len;i++) s2[i]=s1[len-i-1]; s2[len]='\0'; get_extend(s2,len); Ekmp(s1,s2,len,len); for(int i=0;i<len;i++) { if(extend[i]==len-i)suf[i+1]=1; else suf[i+1]=0; } get_extend(s1,len); Ekmp(s2,s1,len,len); for(int i=0;i<len;i++) { if(extend[i]==len-i)pre[len-i]=1;///acacac cacaca else pre[len-i]=0; } int ans=-oo; for(int i=1;i<len;i++) { int mx=0; if(pre[i])mx+=sum[i]; if(suf[i+1])mx+=sum[len]-sum[i]; ans=max(ans,mx); } printf("%d\n",ans); } return 0; } /** 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 abaa 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 acacac */