最小表示法总结

问题解决

一般用于解决一类最小表示或最小串的问题。

问题引入

例题:poj1509

求它的循环串中字典序最小的串的开头。

问题解决

暴力

找到所有的串存下来然后排序,复杂度\(\Theta(n^2)\)的。

诡异做法

建个后缀自动机然后遍历最小的字母边即可。

正经一点的

考虑两个指针\(i\),\(j\),一边扫过去的时候暴力求一下\(i,j\)\(lcp\)的长度,然后比一下\(lcp\)后一位,把大的那个指针往后移那么多位即可。

代码实现

/*
  mail: mleautomaton@foxmail.com
  author: MLEAutoMaton
  This Code is made by MLEAutoMaton
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<iostream>
using namespace std;
#define ll long long
#define REP(a,b,c) for(int a=b;a<=c;a++)
#define re register
#define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
inline int gi(){
	int f=1,sum=0;char ch=getchar();
	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
	return f*sum;
}
const int N=100010;
char s[N];int n;
int main(){
	int T=gi();
	while(T--){
		scanf("%s",s);n=strlen(s);
		int i=0,j=1;
		while(i<n && j<n){
			int k=0;
			while(k<=n && s[(i+k)%n]==s[(j+k)%n])k++;
			if(k>n)break;
			if(s[(i+k)%n]<=s[(j+k)%n])j=j+k+1;
			else i=i+k+1;
			if(i==j)j=i+1;
		}
		printf("%d\n",min(i+1,j+1));
	}
	return 0;
}
posted @ 2019-10-05 21:37  fexuile  阅读(216)  评论(4编辑  收藏  举报