马拉车manacher
目的:线性查找一个串的最长回文子串
时间复杂度:O(n)
len[i]表示以i为中心的回文串的半径,mx即为当前计算回文串最右边字符的最大值,p是中心点mid,mx-i和2*p-1关于p对称
https://blog.csdn.net/csdn_kou/article/details/82917937
hdu3068,板子题,求最长回文长度。
#include<bits/stdc++.h> using namespace std; const int maxn=110000; int t,len[maxn*2]; char S[maxn*2],T[maxn*2],s[maxn*2]; int init(char *str) { int n=strlen(str); for(int i=1,j=0;i<=2*n;j++,i+=2) { s[i]='#'; s[i+1]=str[j]; } s[0]='$'; s[2*n+1]='#'; s[2*n+2]='@'; s[2*n+3]='\n'; return 2*n+1; } void manacher(int n) { int mx=0,p=0; for(int i=1;i<=n;i++) { if(mx>i)len[i]=min(mx-i,len[2*p-i]); else len[i]=1; while(s[i-len[i]]==s[i+len[i]])len[i]++; if(len[i]+i>mx)mx=len[i]+i,p=i; } } int main() { while(scanf("%s",S)!=EOF) { int Len=strlen(S),n=init(S); for(int i=0;i<=n;i++)len[i]=0; manacher(n); int ans=0; for(int i=1;i<=n;i++) { ans=max(ans,len[i]-1); } printf("%d\n",ans); } return 0; }
2019徐州G colorful string,求所有回文子串的value之和,一个串的value为串中字母种类,dfs预处理了第i位前一个a-z的位置,复杂度26*n。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=3e5+100; int t,len[maxn*2]; char S[maxn*2],T[maxn*2],s[maxn*2]; int init(char *str){ int n=strlen(str); for(int i=1,j=0;i<=2*n;j++,i+=2){ s[i]='#'; s[i+1]=str[j]; } s[0]='$'; s[2*n+1]='#'; s[2*n+2]='@'; s[2*n+3]='\n'; return 2*n+1; } void manacher(int n) { int mx=0,p=0; for(int i=1;i<=n;i++){ if(mx>i) len[i]=min(mx-i,len[2*p-i]); else len[i]=1; while(s[i-len[i]]==s[i+len[i]]) len[i]++; if(len[i]+i>mx) mx=len[i]+i,p=i; } } int dp[maxn*2][30],place[30]; int main() { scanf("%s",S); int Len=strlen(S),n=init(S); for(int i=0;i<=n;i++)len[i]=0; manacher(n); ll ans=0; int k=0; for(int i=0;i<26;i++)place[i]=-1000000; for(int i=1;i<=n;i++) { if(i%2==0)place[S[k++]-'a']=i; for(int j=0;j<26;j++)dp[i][j]=place[j]; } for(int i=1;i<=n;i++) { for(int j=0;j<26;j++) { if(i-dp[i][j]<len[i]) { ans+=1ll*(len[i]-(i-dp[i][j]))/2; } } } printf("%lld\n",ans); return 0; }
hdu3613,一个串割成两个串,如果是回文串则val为所有字母val之和,否则为零。
字母的val题目给出,求使总串的val最高的割法的val值。
#include<bits/stdc++.h> using namespace std; const int maxn=5e5+10; int t,len[maxn<<1]; char S[maxn<<1],T[maxn<<1],s[maxn<<1]; int init(char *str) { int n=strlen(str); for(int i=1,j=0;i<=2*n;j++,i+=2) { s[i]='#'; s[i+1]=str[j]; } s[0]='$'; s[2*n+1]='#'; s[2*n+2]='@'; s[2*n+3]='\n'; return 2*n+1; } void manacher(int n) { int mx=0,p=0; for(int i=1;i<=n;i++) { if(mx>i)len[i]=min(mx-i,len[2*p-i]); else len[i]=1; while(s[i-len[i]]==s[i+len[i]])len[i]++; if(len[i]+i>mx)mx=len[i]+i,p=i; } } int main() { int T; scanf("%d",&T); while(T--) { int val[30]={0}; for(int i=0;i<26;i++)scanf("%d",&val[i]); cin>>S; int Len=strlen(S),n=init(S); for(int i=0;i<=n;i++)len[i]=0; manacher(n); int lg=0,rg=0,ans=0; for(int i=0;i<Len;i++)rg+=val[S[i]-'a']; for(int i=1;i<=n;i++) { if(i%2==0) { lg+=val[s[i]-'a']; rg-=val[s[i]-'a']; } else { int l=1,r=2*Len+1,tmplg=0,tmprg=0; if(i!=l&&i!=r) { int mid1=(l+i)>>1,mid2=(i+r)>>1; if(len[mid1]==mid1-l+1)tmplg=lg; if(len[mid2]==r-mid2+1)tmprg=rg; ans=max(ans,tmplg+tmprg); } } } printf("%d\n",ans); } return 0; }
hdu3294,求最早出现的最长回文串的l、r区间,并且转换后输出
#include<bits/stdc++.h> using namespace std; const int maxn=2e5+10; int t,len[maxn<<1]; char S[maxn<<1],T[maxn<<1],s[maxn<<1]; int init(char *str) { int n=strlen(str); for(int i=1,j=0;i<=2*n;j++,i+=2) { s[i]='#'; s[i+1]=str[j]; } s[0]='$'; s[2*n+1]='#'; s[2*n+2]='@'; s[2*n+3]='\n'; return 2*n+1; } void manacher(int n) { int mx=0,p=0; for(int i=1;i<=n;i++) { if(mx>i)len[i]=min(mx-i,len[2*p-i]); else len[i]=1; while(s[i-len[i]]==s[i+len[i]])len[i]++; if(len[i]+i>mx)mx=len[i]+i,p=i; } } int main() { char ch; while(scanf("%c %s",&ch,S)!=EOF) { int Len=strlen(S),n=init(S); for(int i=0;i<=n;i++)len[i]=0; manacher(n); int ans=0,l=0,r=0; for(int i=1;i<=n;i++) { if(len[i]-1>ans) { ans=len[i]-1; l=(i-len[i]+1)/2; r=(i+len[i]-3)/2; } } if(ans<2)printf("No solution!\n"); else { printf("%d %d\n",l,r); for(int i=l;i<=r;i++) { S[i]=S[i]-ch+'a'; if(S[i]>'z')S[i]=S[i]-'z'+'a'-1; if(S[i]<'a')S[i]=S[i]+'z'-'a'+1; } S[r+1]='\0'; printf("%s\n",S+l); } getchar(); } return 0; }
hdu4513,最长递增(不降)回文串,manacher里只需要改个while
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+10; int t,len[maxn*2]; int s[maxn*2],T[maxn*2],S[maxn*2]; int init(int *str,int n) { for(int i=1,j=0;i<=2*n;j++,i+=2) { s[i]=-1; s[i+1]=str[j]; } s[0]=-2; s[2*n+1]=-1; s[2*n+2]=-3; return 2*n+1; } void manacher(int n) { int mx=0,p=0; for(int i=1;i<=n;i++) { if(mx>i)len[i]=min(mx-i,len[2*p-i]); else len[i]=1; while(s[i-len[i]]==s[i+len[i]]&&s[i-len[i]]<=s[i-len[i]+2])len[i]++; if(len[i]+i>mx)mx=len[i]+i,p=i; } } int main() { int T; scanf("%d",&T); while(T--) { int n; scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d",&S[i]); int Len=n,len2=init(S,n); for(int i=0;i<=n;i++)len[i]=0; manacher(len2); int ans=0; for(int i=1;i<=len2;i++) { ans=max(ans,len[i]-1); } printf("%d\n",ans); } return 0; }
...