POJ 1509 Glass Beads

Description

求字符串的最小循环表示.

Sol

SAM.

把原串复制一遍,建出SAM,然后每次选最小的一个跑 \(len\) 次,这就是最小循环表示的最后一个节点,然后 \(x-len+1\) 即为答案.

Code

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;

const int N = 20005;

int n,rt,lst,cnt,l;
int s[N];
int val[N],par[N],go[N][26];

inline int in(int x=0,char ch=getchar()){ while(ch>'9' || ch<'0') ch=getchar();
	while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x; }
inline int read(int l=0,char ch=getchar()){ while(ch>'z' || ch<'a') ch=getchar();
	while(ch>='a' && ch<='z') s[++l]=ch-'a',ch=getchar();return l; }
void Extend(int w){
	int p=lst,np=++cnt;val[np]=val[p]+1,memset(go[np],0,sizeof(go[np]));
	while(p && !go[p][w]) go[p][w]=np,p=par[p];
	if(!p) par[np]=rt;
	else{
		int q=go[p][w];
		if(val[p]+1 == val[q]) par[np]=q;
		else{
			int nq=++cnt;
			val[nq]=val[p]+1;
			memcpy(go[nq],go[q],sizeof(go[q]));
			par[nq]=par[q];
			par[np]=par[q]=nq;
			while(p && go[p][w]==q) go[p][w]=nq,p=par[p];
		}
	}lst=np;
}
int work(){
	int x=rt;
	for(int i=1;i<=l;i++)
		for(int j=0;j<26;j++) if(go[x][j]){ x=go[x][j];break; }
	return val[x]>=l?val[x]-l:val[x];
}
int main(){
	n=in();
	for(int i=1;i<=n;i++){
		l=read(),rt=lst=cnt=1;
		val[rt]=par[rt]=0;memset(go[rt],0,sizeof(go[rt]));
		for(int i=l+1;i<=2*l;i++) s[i]=s[i-l];
		for(int i=1;i<=2*l;i++) Extend(s[i]);
		cout<<work()+1<<endl;
	}
}

  

posted @ 2016-10-13 08:01  北北北北屿  阅读(156)  评论(0编辑  收藏  举报