●POJ 1509 Glass Beads

题链:

http://poj.org/problem?id=1509

题解:

给出一个字符串,有一个操作:把首字符放到末尾,形成新的串。
求任意次操作后,字典序最小的串的首字母在原串中的位置。
(这就是最小表示法?哈)

把原串翻倍,建立后缀自动机。
然后在自动机上从起点往当前节点的较小的字母上跑len步即可。
代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 40050
#define filein(x) freopen(#x".in","r",stdin);
#define fileout(x) freopen(#x".out","w",stdout);
using namespace std;
struct SAM{
	int size,last,p,q,np,nq;
	int step[MAXN],pre[MAXN],ch[MAXN][26];
	int newnode(int a,int b){
		step[size]=a; memcpy(ch[size],ch[b],sizeof(ch[b]));
		return size++;
	}
	void add(int x){
		p=last; last=np=newnode(step[p]+1,0);
		while(p&&!ch[p][x]) ch[p][x]=np,p=pre[p];
		if(!p) pre[np]=1;
		else{
			q=ch[p][x];
			if(step[p]+1!=step[q]){
				nq=newnode(step[p]+1,q);
				pre[nq]=pre[q]; pre[q]=pre[np]=nq;
				while(p&&ch[p][x]==q) ch[p][x]=nq,p=pre[p];
			}
			else pre[np]=q;
		}
	}
	void build(char *S){
		memset(ch[0],0,sizeof(ch[0]));
		size=1; last=newnode(-1,0);
		for(int i=0;S[i];i++) add(S[i]-'a');
	}
}suf;
int find(int len){
	int p=1;
	for(int i=0;i<len;i++)
		for(int j=0;j<26;j++) if(suf.ch[p][j]){
			p=suf.ch[p][j];
			break;
		}
	return suf.step[p]-len+1;
}
int main()
{
	int N,len;
	char S[MAXN];
	scanf("%d",&N);
	for(int cas=1,ans;cas<=N;cas++){
		scanf("%s",S); len=strlen(S);
		for(int i=0;i<len;i++) 
			S[len+i]=S[i]; S[2*len]=0;
		suf.build(S);
		ans=find(len)+1;
		printf("%d\n",ans);
	}
	return 0;
}
posted @ 2017-12-05 17:51  *ZJ  阅读(123)  评论(0编辑  收藏  举报