题意 给你多组n 每组n个字符串 输出最小表示法开始的下标
做法 我们把2*字符串存入SAM中 然后只要按字典序贪心的取最小的 返回maxlen[now]-len+1即使需要的答案
/*
if you can't see the repay
Why not just work step by step
rubbish is relaxed
to ljq
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <cmath>
#include <map>
#include <stack>
#include <set>
#include <sstream>
#include <vector>
#include <stdlib.h>
#include <algorithm>
using namespace std;
const int MAX_N = 100010;
char str[MAX_N];
int len;
struct SAM
{
int fa[MAX_N],ch[MAX_N][26],maxlen[MAX_N],tot,last;
void init()
{
tot = last = 1;maxlen[1] = fa[1] = 0;
memset(ch[1],0,sizeof(ch[1]));
}
void add(int x)
{
int np = ++tot,p = last;last = np;
maxlen[np] = maxlen[p] + 1;
memset(ch[np],0,sizeof(ch[np]));
while(p&&!ch[p][x]) ch[p][x] = np,p = fa[p];
if(!p) fa[np] = 1;
else
{
int q = ch[p][x];
if(maxlen[q]==maxlen[p]+1) fa[np] = q;
else
{
int nq = ++tot;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq] = fa[q],fa[np] = fa[q] = nq;
maxlen[nq] = maxlen[p] + 1;
while(p&&ch[p][x]==q) ch[p][x]=nq,p = fa[p];
}
}
}
void solve()
{
int NOW = 1;
for(int i = 0;i<len;++i)
{
for(int j = 0;j<26;j++)
{
if(ch[NOW][j])
{
NOW = ch[NOW][j];
break;
}
}
}
printf("%d\n",maxlen[NOW]-len+1);
}
}S;
int main()
{
//ios::sync_with_stdio(false);
//freopen("a.txt","r",stdin);
//freopen("b.txt","w",stdout);
int n;
while(~scanf("%d",&n))
{
while(n--)
{
S.init();
scanf("%s",str);
len = strlen(str);
for(int i = 0; i<len; ++i)
S.add(str[i]-'a');
for(int i = 0; i<len; ++i)
S.add(str[i]-'a');
S.solve();
}
}
//fclose(stdin);
//fclose(stdout);
//cout << "time: " << (long long)clock() * 1000 / CLOCKS_PER_SEC << " ms" << endl;
return 0;
}