【kmp】【后缀数组】【连续重复子串】Power Strings POJ2406

Power Strings

Time Limit: 3000MS Memory Limit: 65536K
Total Submissions: 25921 Accepted: 10857

Description

Given two strings a and b we define a*b to be their concatenation. For example, if a = "abc" and b = "def" then a*b = "abcdef". If we think of concatenation as multiplication, exponentiation by a non-negative integer is defined in the normal way: a^0 = "" (the empty string) and a^(n+1) = a*(a^n).

Input

Each test case is a line of input representing s, a string of printable characters. The length of s will be at least 1 and will not exceed 1 million characters. A line containing a period follows the last test case.

Output

For each s you should print the largest n such that s = a^n for some string a.

Sample Input

abcd
aaaa
ababab
.

Sample Output

1
4
3

Hint

This problem has huge input, use scanf instead of cin to avoid time limit exceed.

Source





先说说后缀数组,比如ababab

我们枚举重复串的长度len

比如len=2

如果说此时满足要求,那么后缀 0 和 后缀 2 的公共部分必定有 n - len 的长度

后缀 0 :ababab
后缀 2 :abab

所以穷举 len 即可


复杂度O(N),然后后缀数组O(NlogN) + O(N)

一交poj,超时了。。。。。


后来看了网上题解才发现后缀数组确实要超时。。。都是用kmp写的


(以下转自别人博客)

对于数组s[0~n-1],计算next[0~n](多计算一位)。

考虑next[n],假设t=n-next[n],如果n%t==0,则t就是问题的解,否则解为1。

这样考虑:

比如字符串"abababab",

            a  b a b a b a b *

next     -1 0 1 2 3 4 5 6  7

考虑这样的模式匹配,将"abababab#"当做主串,"abababab*"当做模式串,于是进行匹配到n(n=8)时,出现了不匹配:

 主串      abababab#

 模式串   abababab*

于是模式串需要回溯到next[*]=7,这之前的主串和模式串对应相等,于是需要模式串向右滚动的位移是d=n-next[n]=2,即:

            123456789 

主串      abababab#

模式串       abababab*

于是可以看出,s[0~1]=s[3~4]=s[5~6]=s[7~8]。

所以位移d=n-next[n]可以看作是构成字符串s的字串(如果n%d==0,存在这样的构成),相应的重复次数也就是n/d。



这样O(N)就可以了


测评情况(POJ)(超时的是后缀数组)



C++ AC Code(kmp)

/*http://blog.csdn.net/jiangzh7
By Jiangzh*/
#include<cstdio>
#include<cstring>

char s[1000000+10];
int len;
int next[1000000+10];

void getnext()
{
	memset(next,0,sizeof(next));
	next[0]=-1;
	int j=0,k=-1;
	while(j<len)
	{
		if(k==-1||s[j]==s[k]) next[++j]=++k;
		else k=next[k];
	}
}

int main()
{
	freopen("poj2406.in","r",stdin);
	freopen("2406kmp.out","w",stdout);
	while(1)
	{
		memset(s,0,sizeof(s));
		scanf("%s",s);len=strlen(s);
		if(!strcmp(s,".")) break;
		getnext();
		//for(int i=0;i<=len;i++) printf("%d ",next[i]);puts("");
		if(len!=next[len] && len%(len-next[len])==0) printf("%d\n",len/(len-next[len]));
		else printf("1\n");
	}
	return 0;
}



C++ TLE Code(Suffix Array)

/*http://blog.csdn.net/jiangzh7
By Jiangzh*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1000000+10;
char s[N];
int rank[N],sa[N];
int c[N],tmp[N];
int height[N];
int lcp[N];

bool cmp(int *r,int a,int b,int l)
{ return r[a]==r[b] && r[a+l]==r[b+l]; }

void DA(int n,int m)
{
	int i,j,p,*x=rank,*y=tmp;
	memset(c,0,sizeof(c));
	for(i=0;i<n;i++) c[ x[i]=s[i] ]++;
	for(i=1;i<m;i++) c[i]+=c[i-1];
	for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
	for(j=1,p=1;p<n;j*=2,m=p)
	{
		for(p=0,i=n-j;i<n;i++) y[p++]=i;
		for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
		memset(c,0,sizeof(c));
		for(i=0;i<n;i++) c[x[y[i]]]++;
		for(i=1;i<m;i++) c[i]+=c[i-1];
		for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
		swap(x,y); x[sa[0]]=0;
		for(p=1,i=1;i<n;i++)
			x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;
	}
	for(i=0;i<n;i++) rank[sa[i]]=i;
	int k=0;
	for(i=0;i<n;height[x[i++]]=k)
		for(k?k--:0,j=sa[x[i]-1];s[i+k]==s[j+k];k++);
}

void work()
{
	int n=strlen(s);s[n++]='$';
	DA(n,'z'+1);
	/*for(int i=0;i<n;i++)
	{
		printf("%d %d ",sa[i],height[i]);
		puts(s+sa[i]);
	}*/
	lcp[rank[0]]=0x3f3f3f3f;
	for(int i=rank[0]-1;i>0;i--) lcp[i]=min(lcp[i+1],height[i+1]);
	for(int i=rank[0]+1;i<n;i++) lcp[i]=min(lcp[i-1],height[i]);
	//for(int i=0;i<n;i++) printf("%d ",lcp[i]);puts("");
	for(int len=1;len<n;len++)
		if((n-1)%len==0)
		{
			if(lcp[rank[len]]==(n-1)-len)
			{
				printf("%d\n",(n-1)/len);
				break;
			}
		}
}

int main()
{
	freopen("poj2406.in","r",stdin);
	freopen("poj2406.out","w",stdout);
	while(1)
	{
		memset(sa,0,sizeof(sa));
		memset(rank,0,sizeof(rank));
		memset(c,0,sizeof(c));
		memset(tmp,0,sizeof(tmp));
		memset(s,0,sizeof(s));
		scanf("%s",s);
		if(!strcmp(s,".")) break;
		work();
	}
	return 0;
}










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值