最近打算把SAM撿回來,找個水題先練練手...這題是給一個字符串,首尾相連成環,求一個位置,使得從這個位置開始走一圈得到的串字典序最小。方法很多,後綴自動機也能做,把原串複製兩邊,一次插入到自動機中,然後從根節點開始,從小打到走len步,當前的位置就是最小字典序的串的位置了..
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <memory.h>
#include <queue>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn=20100;
const int S=26;
int tot,len;
int n,m;
int wtop[maxn<<1];
int c[maxn<<1];
int k,ans;
struct node
{
node *pre,*go[S];
int val,id;
}*tail,*root,que[maxn<<1],top[maxn<<1];
char str[maxn],s[maxn],ss[maxn];
inline int idx(char c)
{
return c-'a';
}
struct SAM
{
void init()
{
memset(que,0,sizeof que);
tot=0;
len=1;
root=tail=&que[tot++];
root->id=0;
root->val=0;
}
void add(int c,int l)
{
node* p=tail;
node* np=&que[tot++];
np->val=l;
np->id=tot-1;
while(p && p->go[c]==NULL) p->go[c]=np,p=p->pre;
if (p==NULL) np->pre=root;
else
{
node* q=p->go[c];
if (p->val+1==q->val) np->pre=q;
else
{
node *nq=&que[tot++];
*nq=*q;
nq->id=tot-1;
nq->val=p->val+1;
np->pre=q->pre=nq;
while(p && p->go[c]==q) p->go[c]=nq,p=p->pre;
}
}
tail=np;
}
void debug_suff()
{
for (int i=0; i<tot; i++)
{
for (int c=0; c<S; c++)
if (que[i].go[c])
{
cout<<que[i].id<<" "<<que[i].go[c]->id<<endl;
}
}
}
void debug_pre()
{
for (int i=1; i<tot; i++)
cout<<que[i].id<<" "<<que[i].pre->id<<endl;
}
}sam;
int main()
{
// freopen("in.txt","r",stdin);
int tt;
scanf("%d",&tt);
while(tt--)
{
scanf("%s",s);
sam.init();
int l=strlen(s);
for (int i=0; i<l; i++)
sam.add(idx(s[i]),len++);
for (int i=0; i<l; i++)
sam.add(idx(s[i]),len++);
// sam.debug_suff();
// puts("-----------------------------");
// sam.debug_pre();
node* rt=root;
for (int i=0; i<l; i++)
for (int c=0; c<S; c++)
{
if (rt->go[c])
{
rt=rt->go[c];
break;
}
}
printf("%d\n",rt->val-l+1);
}
return 0;
}