POJ 1509 后缀自动机

来源:互联网 发布:河南省公安厅网络 编辑:程序博客网 时间:2024/05/01 13:32

题意:给出一个圆圈,圆圈上顺时针有一些字符,现在要从某个字符前边断开,得到一个以这个字符开头的字符串,使得得到的字符串字典序最小。如果多解,输出最小的断点。


题解:把字符串copy一次,放到原串后边,使得长度*2,然后放到SAM中,从Root开始按照字典序走贪心len步(如果不能走就提前break) 搞定。


Code:

#include<cstdio>#include<cstring>using namespace std;const int maxn = 1e4+100;char s[maxn];int n;int L;struct SAM{int last,cnt,nxt[maxn*2][26],fa[maxn*2],len[maxn*2];void init(){last=cnt=1;memset(nxt[1],0,sizeof nxt[1]);fa[1]=len[1]=0;}int newnode(){++cnt;memset(nxt[cnt],0,sizeof nxt[cnt]);fa[cnt]=len[cnt]=0;return cnt;}void add(int c){int p=last;int np = newnode();last = np;len[np]=len[p]+1;while (p&&!nxt[p][c]){nxt[p][c]=np;p=fa[p];}if (!p){fa[np]=1;}else{int q = nxt[p][c];if (len[q]==len[p]+1){fa[np]=q;}else{int nq=newnode();len[nq]=len[p]+1;memcpy(nxt[nq],nxt[q],sizeof (nxt[q]));fa[nq]=fa[q];fa[np]=fa[q]=nq;while (nxt[p][c]==q){nxt[p][c]=nq;p=fa[p];}}}}int query(){int now =1;for (int i=0;i<L;i++){bool flag = false;for (int j=0;j<=25;j++){if (nxt[now][j]){flag = true;now = nxt[now][j];break;}}if (!flag){break;}}return len[now]+1-L;}}sam;int main(){scanf("%d",&n);while (n--){sam.init();scanf("%s",s);L = strlen(s);for (int i=0;i<L;i++){sam.add(s[i]-'a');}for (int i=0;i<L;i++){sam.add(s[i]-'a');}printf("%d\n",sam.query());}return 0;}