洛谷P1368 【模板】最小表示法

Description

求与S循环同构的所有字符串中字典序最小的字符串

Solution

考虑对于一对字符串 A , B A,B A,B, 它们在原字符串 S S S 中的起始位置分别为 i , j i,j i,j,且它们的前 k k k 个字符均相同,即 S [ i . . . i + k − 1 ] = S [ j . . . j + k − 1 ] S[i...i+k-1]=S[j...j+k-1] S[i...i+k1]=S[j...j+k1]
S [ i + k ] > S [ j + k ] S[i+k]>S[j+k] S[i+k]>S[j+k],则对于任意一个字符串 S i + p S_{i+p} Si+p(表示以 i + p i+p i+p 为起始位置的字符串, p ∈ [ 0 , k ] ) p \in [0, k]) p[0,k],字符串 S j + p S_{j+p} Sj+p一定比它更优。
所以比较时可以跳过 [ i , i + k ] [i,i+k] [i,i+k],直接从 i + k + 1 i+k+1 i+k+1开始继续比较
停止条件是 i , j , k i,j,k i,j,k中有一个 ≥ n ≥n n,因为这样就循环了,此时 m i n ( i , j ) min(i,j) min(i,j)就是最终答案的起始位置
下面处理一个细节问题,为什么选 m i n ( i , j ) min(i,j) min(i,j),而不用 c h e c k check check一下
k = n k=n k=n k k k每次只加一,所以不会大于), i , j i,j i,j等价
i ≥ n i≥n in
通过我们的比较过程,我们可以得知,在 m a x ( i , j ) max(i,j) max(i,j)之前除 i , j i,j i,j的位置作起始位置一定不会比 i , j i,j i,j更优(用数规易证)
我们将操作后的 i i i记作 i ′ i' i
i ′ ≥ n i'≥n in,上一步操作一定是 i + = k + 1 i+=k+1 i+=k+1,即 i ′ = i + k + 1 i'=i+k+1 i=i+k+1,且此时 k < n k<n k<n
此时的 i ′ i' i i ′ − n i'-n in等价,由 k < n k<n k<n,有 i ′ − n ≤ i ≤ m a x ( i , j ) i'-n≤i≤max(i,j) inimax(i,j),而 i i i本身就是要 o u t out out的,所以 i ′   o u t ! i'\space out! i out
j ≥ n j≥n jn同理

Code

#include<bits/stdc++.h>
using namespace std;
#define gc getchar
inline int rd(){
	int x=0,fl=1;char ch=gc();
	for (;ch<48||ch>57;ch=gc())if(ch=='-')fl=-1;
	for (;48<=ch&&ch<=57;ch=gc())x=x*10+(ch^48);
	return x*fl;
}
int n,i,j,k,t,s[300003];
int main(){
	for (n=rd();i<n;i++) s[i]=rd();
	for (i=0,j=1;i<n && j<n && k<n;){
		t=s[(i+k)%n]-s[(j+k)%n];
		if (!t) k++;
		else (t>0?i:j)+=k+1,j+=(i==j),k=0;
	}
	i=min(i,j);
	for (k=0;k<n;k++) printf("%d ",s[(i+k)%n]);
}
posted @ 2018-12-21 11:31  Mingoal  阅读(19)  评论(0)    收藏  举报  来源