【知识】字符串 最小表示法
问题描述:
最小表示法是字符串 \(S\) 循环同构的所有字符串中,字典序最小的串是哪个。
最小表示法:
考虑对于一对字符串 \(A,B\), 它们在原字符串 \(S\) 中的起始位置分别为 \(i,j\), 且它们的前 \(k\) 个字符均相同,即
\[S[i \cdots i+k-1]=S[j \cdots j+k-1]
\]
不妨先考虑 \(S[i+k]>S[j+k]\) 的情况,我们发现起始位置下标 \(l\) 满足 \(i\le l\le i+k\) 的字符串均不能成为答案。因为对于任意一个字符串 \(S_{i+p}\)(表示以 \(i+p\) 为起始位置的字符串,\(p \in [0, k]\))一定存在字符串 \(S_{j+p}\) 比它更优。
所以我们比较时可以跳过下标 \(l\in [i,i+k]\), 直接比较 \(S_{i+k+1}\)
时间复杂度 \(\mathcal{O}(n)\)
#include<bits/stdc++.h>
using namespace std;
int n,ans,A[300009];
int Min_show(){
int i=0,j=1,k=0;
while(i<n&&j<n&&k<n){
if(A[(i+k)%n]==A[(j+k)%n]) k++;
else{
if(A[(i+k)%n]>A[(j+k)%n])i+=k+1;
else j+=k+1;
if(i==j)i++;
k=0;
}
}
return min(i,j);
}
int main(){
cin >> n;
for(int i=0;i<n;i++)
cin >> A[i];
ans=Min_show();
for(int i=0;i<n;i++)
cout << A[(i + ans) % n] << " ";
return 0;
}