Link
Difficulty
算法难度8,思维难度5,代码难度6
Description
给定一个串,你可以把开头字符放到结尾,这个操作可以执行任意次
求使得最终串字典序最小的起点在哪个位置
多组询问,单组长度不超过 10000 10000 10000
Solution
把字符串复制一遍接在后面,然后建SAM
从根节点开始走,每次走可以走的最小边,走n步到达的点就是答案
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
inline int read(){
int x=0,f=1;char ch=' ';
while(ch<'0' || ch>'9'){if(ch=='0')f=-1;ch=getchar();}
while(ch>='0' && ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return f==1?x:-x;
}
const int N=1e5+5;
namespace SAM{
int last,cnt;
int ch[N][26],l[N],fa[N];
inline void insert(int c){
int p=last,np=++cnt;last=np;l[np]=l[p]+1;
for(;p && !ch[p][c];p=fa[p])ch[p][c]=np;
if(!p)fa[np]=1;
else{
int q=ch[p][c];
if(l[q]==l[p]+1)fa[np]=q;
else{
int nq=++cnt;l[nq]=l[p]+1;
memcpy(ch[nq],ch[q],sizeof ch[nq]);
fa[nq]=fa[q];fa[q]=fa[np]=nq;
for(;ch[p][c]==q;p=fa[p])ch[p][c]=nq;
}
}
}
inline void init(){
for(int i=1;i<=cnt;++i){
l[i]=fa[i]=0;
memset(ch[i],0,sizeof ch[i]);
}
last=cnt=1;
}
};
int T,n;
char ch[N];
int main(){
T=read();
while(T--){
memset(ch,0,sizeof ch);
SAM::init();
scanf("%s",ch+1);
n=strlen(ch+1);
for(int i=1;i<=n;++i)SAM::insert(ch[i]-'a');
for(int i=1;i<=n;++i)SAM::insert(ch[i]-'a');
int now=1;
for(int i=1;i<=n;++i)
for(int k=0;k<26;++k)
if(SAM::ch[now][k]){
now=SAM::ch[now][k];
break;
}
printf("%d\n",SAM::l[now]-n+1);
}
return 0;
}