最近打算把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;
}