1 条题解
-
0
自动搬运
来自洛谷,原作者为

ZHR100102
kipfel 可爱喵搬运于
2025-08-24 22:50:03,当前版本为作者最后更新于2024-12-10 23:48:39,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
哈希
思路
显然正着做一遍哈希,倒着做一遍哈希,然后枚举回文中心即可。
时间复杂度 。
代码
#include <bits/stdc++.h> #define fi first #define se second #define lc (p<<1) #define rc ((p<<1)|1) using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pi; const int N=400005; const ull base=13331; ull phash[N],shash[N],pw[N]; int n,ans; char s[N]; void dohash() { pw[0]=1; for(int i=1;i<N;i++)pw[i]=pw[i-1]*base; for(int i=1;i<=n;i++)phash[i]=phash[i-1]*base+s[i]; for(int i=n;i>=1;i--)shash[i]=shash[i+1]*base+s[i]; } ull gethash(int op,int l,int r) { if(op==0)return (phash[r]-phash[l-1]*pw[r-l+1]); return (shash[l]-shash[r+1]*pw[r-l+1]); } int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin>>n>>s+1; ans=n-1; if(n==1) { cout<<0; return 0; } dohash(); for(int i=1;i<=n;i++) { if(i-1>=n-(i+1)+1) { int len=n-(i+1)+1; if(gethash(0,i-1-len+1,i-1)==gethash(1,i+1,i+1+len-1)) { ans=min(ans,i-1-len); } } if(i>=n-(i+1)+1) { int len=n-(i+1)+1; if(gethash(0,i-len+1,i)==gethash(1,i+1,i+1+len-1)) { ans=min(ans,i-len); } } } cout<<ans; return 0; }哈希的代码又臭又长,肯定不是这题的最优解。
KMP
思路
我们考虑这题要求的本质是什么,显然是求字符串 最长的回文后缀的长度 ,那么答案就是 。因为剩下的那些必须对称过去。
那么如何求最长的回文后缀呢?我们可以先把字符串 反转为 ,把后缀转化为前缀便于处理。
由于回文串正着读和反着读都一样,可以发现回文后缀满足是字符串 的一段前缀,也是字符串 的一段后缀。
因此如果字符串 的一段前缀与字符串 的一段后缀相等,就说明这是一个合法的回文后缀。
如果要让这个后缀最长,那么显然是 KMP 的 ,就求出来了。
实现上,我们可以将最后的主串设置为 与任意一个分隔符与 拼接起来的字符串,然后做一遍 KMP 即可。
时间复杂度 。
代码
非常简短,注意字符串开两倍的长度。
#include <bits/stdc++.h> using namespace std; const int N=800005; int n,ne[N]; char s[N]; int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin>>n>>s+n+2; s[n+1]='%'; for(int i=1,j=2*n+1;i<=n;i++,j--)s[i]=s[j]; int now=0; for(int i=2;i<=2*n+1;i++) { while(now&&s[now+1]!=s[i])now=ne[now]; if(s[now+1]==s[i])now++; ne[i]=now; } cout<<n-ne[2*n+1]; return 0; }
- 1
信息
- ID
- 8863
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者