题解:P13270 【模板】最小表示法
MoCaRabbit · · 题解
最小表示法竟然更新模板题了!
那我就要来写题解了。
暴力解法
枚举循环同构串的第一个位置,然后暴力用字符串挨个比较的方法比较。
时间复杂度
优化解法
考虑如何优化暴力解法。
首先,这循环同构看起来有点烦,所有我们选择复制一份到字符串后面。
然后再考虑如何快速进行字符串比较。
首先字符串比较需要找到字符串第一个不相等的位置。
这里我们可以用前缀哈希 + 二分 / 倍增的方式。
就可以
代码如下。
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e7+10;
int n;
string s;
unsigned int h[maxn],p[maxn];
unsigned int gethash(int l,int r){
return h[r]-h[l-1]*p[r-l+1];
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>s,s=" "+s+s;
p[0]=1;
for(int i=1;i<=2*n;i++) h[i]=h[i-1]*131+s[i],p[i]=p[i-1]*131;
int st=1;
for(int i=2;i<=n;i++){
int ans=-1;
for(int p=30;p>=0;p--){//利用哈希比较字符串
if(ans+(1<<p)>n) continue;
if(gethash(st,st+ans+(1<<p))==gethash(i,i+ans+(1<<p))) ans+=(1<<p);
}
// cout<<ans<<'\n';
if(ans!=n) if(s[i+ans+1]<s[st+ans+1]) st=i;
}
for(int i=st;i<=st+n-1;i++) cout<<s[i];
return 0;
}
暴力的优化解法
算法介绍
这里我们尽量尝试去排除更多的无效状态
假设我们现在要比较第
我们暴力找到一个
如果没找到一个合适的
如果
因为对于一个
这时,
如果
然后做完了?做完了。
代码时间
代码十分简短。
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e7;
int n;
string s;
int main() {
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>s,s=" "+s+s;
int st=1;
for(int i=2;i<=n;){
int j=0;
for(j=0;j<n && s[st+j]==s[i+j];j++);
if(j==n) break;
if(s[st+j]>s[i+j]){
int m=st;
st=i,i=max(i+1,m+j+1);
}
else i+=j+1;
}
for(int i=st;i<=st+n-1;i++) cout<<s[i];
return 0;
}
时间复杂度证明
对于
对于另一种情况,
所以总复杂度