1. 程式人生 > 實用技巧 >Luogu P1368 【模板】最小表示法

Luogu P1368 【模板】最小表示法

https://www.luogu.com.cn/problem/P1368

題面

給定一個字串,求出最小的迴圈表示

分析

先擴充套件兩倍
給定兩個起點\(i,j\),找到第一個\(a[i+k]!=a[j+k]\),判斷大小
不妨假設\(a[i+k]>a[j+k]\)
則對於起點\(a\in [i,i+k]\)總會比起點\(b\in [j,j+k]\)
\(\therefore i=i+k+1\)
因為\((i,j)\)只加,所以均攤\(O(n)\)

 #include<bits/stdc++.h>
using namespace std;

const int N=6e5+5;
int n,a[N];

int main() {
	scanf("%d",&n);
	for(int i=1;i<=n;i++) {
		scanf("%d",&a[i]),a[i+n]=a[i];
	}
	int i=1,j=2;
	while(i<=n&&j<=n) {
		int k;
		for(k=0;k<=n&&a[i+k]==a[j+k];k++);
		if(k==n) {
			for(int l=1;l<=n;l++) {
				printf("%d ",a[l]);
			}
			return 0;
		}
		if(a[i+k]>a[j+k]) i+=k+1; else j+=k+1;
		if(i==j) j++;
	}
	if(i>n) {
		for(int k=j;k<=n;k++) printf("%d ",a[k]);
		for(int k=1;k<j;k++) printf("%d ",a[k]);
	} else {
		for(int k=i;k<=n;k++) printf("%d ",a[k]);
		for(int k=1;k<i;k++) printf("%d ",a[k]);
	}
	return 0;
}