最小表示法总结
问题解决
一般用于解决一类最小表示或最小串的问题。
问题引入
例题: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;
}