Luogu P9606 CERC2019 ABB 题解 [ 绿 ] [ KMP ] [ 字符串哈希 ]
ABB:KMP 的做法非常巧妙。
哈希
思路
显然正着做一遍哈希,倒着做一遍哈希,然后枚举回文中心即可。
时间复杂度
代码
#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 的
实现上,我们可以将最后的主串设置为
时间复杂度
代码
非常简短,注意字符串开两倍的长度。
#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;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战