题目: click here
找一个字典序最小的循环链的起始点。
SAM化后,从根节点每次选择子节点最小的,走n步就好了。。
#include <cstdio>
#include <cstdlib>
#include <cstring>
const int MAX_NODES = 3555555;
const int N = 1111111;
struct node{
struct node *ch[26];
struct node *f;
int mx;
void init(){
memset(ch,0,sizeof(ch));
f = 0;
}
}*root,*cnt,*tail,pool[MAX_NODES];
char s[N],ts[N];
int n;
void insert(int c,int len){
node *p = tail, *np = cnt++;
for( ; p && !p->ch[c] ; p = p->f) p->ch[c] = np;
np->mx = len;
tail = np;
if(!p) np->f = root;
else
if( p->ch[c]->mx == p->mx+1) np->f = p->ch[c];
else{
node *q = p->ch[c], *r = cnt++;
*r = *q;
r->mx = p->mx+1;
q->f = np->f = r;
for( ; p && p->ch[c] == q ; p = p->f) p->ch[c] = r;
}
}
void init_suffix_auto(char s[]){
int len = 0;
tail = cnt = root = pool; cnt++ , root->init();
for(int i = 0;i < (n<<1) ;i++)
pool[i].init();
for( ; s[len] ; len++){
insert(s[len] - 'a', len+1);
}
}
int rank[N];
int dfs(int u,int step){
node * q = &pool[u];
if(step == n){
return q->mx;
}
for(int i = 0;i < 26;i++){
if(q->ch[i]){
return dfs(q->ch[i]-root,step+1);
}
}
return 0;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%s",ts);
n = strlen(ts);
strcpy(s,ts);
strcpy(s+n,ts);
init_suffix_auto(s);
int ans = dfs(0,0)-n;
printf("%d\n",ans+1);
}
return 0;
}