【POJ3693】Maximum repetition substring 后缀数组恶心题

转载请注明出处:http://blog.csdn.net/vmurder/article/details/42677359

其实我就是觉得原创的访问量比未授权盗版多有点不爽233。。。

题意:

给一个字符串,然后找一个子串,使子串满足其中连续重复子串最多。

比如ababab,重复次数为3,ababa,重复次数为1(abab是两次)

恶心在于还要输出最小字典序。

题解网上都有,不发了。

代码:

<span style="font-family:KaiTi_GB2312;font-size:18px;">#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 101000
#define LOGN 20
#define inf 0x3f3f3f3f
using namespace std;
char s[N];
int len;
int sa[N],rank[N],height[N];
int sa2[N],rank2[N],height2[N];

int stk[N],top,cnt[N];
int val[N],_val[N];
inline bool cmp(int x,int y,int hl)
{return val[x]==val[y]&&((x+hl>=len&&y+hl>=len)||(x+hl<len&&y+hl<len&&val[x+hl]==val[y+hl]));}
void SA()
{
	int i,j,k,hl,lim=300;
	for(i=0;i<lim;i++)cnt[i]=0;
	for(i=0;i<len;i++)cnt[val[i]=s[i]]++;
	for(i=1;i<lim;i++)cnt[i]+=cnt[i-1];
	for(i=len-1;i>=0;i--)sa[--cnt[val[i]]]=i;

	for(k=0;;k++)
	{
		top=0,hl=1<<k;
		for(i=0;i<len;i++)if(sa[i]+hl>=len)stk[++top]=sa[i];
		for(i=0;i<len;i++)if(sa[i]>=hl)stk[++top]=sa[i]-hl;

		for(i=0;i<lim;i++)cnt[i]=0;
		for(i=0;i<len;i++)cnt[val[i]]++;
		for(i=1;i<lim;i++)cnt[i]+=cnt[i-1];
		for(i=len;i>0;i--)sa[--cnt[val[stk[i]]]]=stk[i];

		for(i=lim=0;i<len;lim++)
		{
			for(j=i;j<len-1&&cmp(sa[j],sa[j+1],hl);j++);
			for(;i<=j;i++)_val[sa[i]]=lim;
		}
		for(i=0;i<len;i++)val[i]=_val[i];
		if(lim==len)break;
	}
	for(i=0;i<len;i++)rank[sa[i]]=i;
	for(k=i=0;i<len;i++)
	{
		if(k)k--;
		if(!rank[i])continue;
		while(s[i+k]==s[sa[rank[i]-1]+k])k++;
		height[rank[i]]=k;
	}
	lim=300;
	for(i=0;i<lim;i++)cnt[i]=0;
	for(i=0;i<len;i++)cnt[val[i]=s[len-i-1]]++;
	for(i=1;i<lim;i++)cnt[i]+=cnt[i-1];
	for(i=len-1;i>=0;i--)sa2[--cnt[val[i]]]=i;

	for(k=0;;k++)
	{
		top=0,hl=1<<k;
		for(i=0;i<len;i++)if(sa2[i]+hl>=len)stk[++top]=sa2[i];
		for(i=0;i<len;i++)if(sa2[i]>=hl)stk[++top]=sa2[i]-hl;

		for(i=0;i<lim;i++)cnt[i]=0;
		for(i=0;i<len;i++)cnt[val[i]]++;
		for(i=1;i<lim;i++)cnt[i]+=cnt[i-1];
		for(i=len;i>0;i--)sa2[--cnt[val[stk[i]]]]=stk[i];

		for(i=lim=0;i<len;lim++)
		{
			for(j=i;j<len-1&&cmp(sa2[j],sa2[j+1],hl);j++);
			for(;i<=j;i++)_val[sa2[i]]=lim;
		}
		for(i=0;i<len;i++)val[i]=_val[i];
		if(lim==len)break;
	}
	for(i=0;i<len;i++)rank2[sa2[i]]=i;
	for(k=i=0;i<len;i++)
	{
		if(k)k--;
		if(!rank2[i])continue;
		while(s[len-i-k-1]==s[len-sa2[rank2[i]-1]-k-1])k++;
		height2[rank2[i]]=k;
	}
}
int st[N][LOGN],St[N][LOGN],logf[N];
int ST[N][LOGN],sT[N][LOGN];
void RMQ_init()
{
	int i,j,k,sk;
	for(i=0;i<len;i++)
	{
		st[i][0]=height[i];
		St[i][0]=height2[i];
		sT[i][0]=rank[i];
		ST[i][0]=i;
	}
	for(i=2;i<N;i++)logf[i]=logf[i>>1]+1;
	for(j=1;k=(1<<j),k<len;j++)
		for(sk=(k>>1),i=0;i+k-1<len;i++)
		{
			st[i][j]=min(st[i][j-1],st[i+sk][j-1]),
			St[i][j]=min(St[i][j-1],St[i+sk][j-1]);
			if(sT[i][j-1]<sT[i+sk][j-1])
			{
				sT[i][j]=sT[i][j-1];
				ST[i][j]=ST[i][j-1];
			}
			else {
				sT[i][j]=sT[i+sk][j-1];
				ST[i][j]=ST[i+sk][j-1];
			}
		}

}
inline int querypre(int L,int R) // 两个点最长相同前串
{
	if(L>R)swap(L,R);L++;
	int ll=logf[R-L];
	return min(St[L][ll],St[R-(1<<ll)+1][ll]);
}
inline int querysuc(int L,int R) // 两个点最长相同后串
{
	if(L>R)swap(L,R);L++;
	int ll=logf[R-L];
	return min(st[L][ll],st[R-(1<<ll)+1][ll]);
}
inline int query(int L,int R) // 求一段区间内最小rank
{
	if(L>R)swap(L,R);
	int ll=logf[R-L];
	return sT[L][ll]<sT[R-(1<<ll)+1][ll]?ST[L][ll]:ST[R-(1<<ll)+1][ll];
}
int ans,id,id2;
int main()
{
//	freopen("test.in","r",stdin);
	int i,j,k,g=0;
	int l,r,pre,suc,ll;
	while(scanf("%s",s),s[0]!='#')
	{
		printf("Case %d: ",++g);
		len=strlen(s);
		SA();
		RMQ_init();
		ans=1,id=0,id2=1;
		for(i=len>>1;i;i--) // 枚举 重复部分 长度
		{
			for(j=0;j+i<len;j+=i)
			{
				pre=querypre(rank2[len-j-1],rank2[len-j-i-1]);
				suc=querysuc(rank[j],rank[j+i]);
				ll=(pre&&suc)?(pre+suc-1):(pre+suc);
				if(k=ll/i)
				{
					l=j-pre+(pre?1:0);
					r=l+ll-k*i;
					int mx=query(l,r);
					k++;
					if(ans<k||(ans==k&&rank[id]>=rank[mx]))
						ans=k,id=mx,id2=id+k*i;
				}
			}
		}
		if(ans==1)printf("%c\n",s[sa[0]]);
		for(i=id;i<id2;i++)printf("%c",s[i]);
		puts("");
	}
	return 0;
}
</span>
时间: 2024-12-17 15:30:31

【POJ3693】Maximum repetition substring 后缀数组恶心题的相关文章

poj3693 Maximum repetition substring 后缀数组

http://poj.org/problem?id=3693 Maximum repetition substring Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7241   Accepted: 2162 Description The repetition number of a string is defined as the maximum number R such that the string can b

POJ3693:Maximum repetition substring(后缀数组+RMQ)

Description The repetition number of a string is defined as the maximum number R such that the string can be partitioned into R same consecutive substrings. For example, the repetition number of "ababab" is 3 and "ababa" is 1. Given a

poj 3693 Maximum repetition substring(后缀数组)

题目链接:poj 3693 Maximum repetition substring 题目大意:求一个字符串中循环子串次数最多的子串. 解题思路:对字符串构建后缀数组,然后枚举循环长度,分区间确定.对于一个长度l,每次求出i和i+l的LCP,那么以i为起点,循环子串长度为l的子串的循环次数为LCP/l+1,然后再考虑一下从i-l+1~i之间有没有存在增长的可能性. #include <cstdio> #include <cstring> #include <vector>

hdu 2459 Maximum repetition substring(后缀数组)

题目链接:hdu 2459 Maximum repetition substring 题意: 让你找一个重复最多的子串,并且输出. 题解: 这个是论文题,看的cxlove的题解,不是很理解为什么这样就能完全找完,当作结论使吧. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;++i) 3 using namespace std; 4 namespace suffixarray{ 5 #define FN(n) f

Maximum repetition substring 后缀数组

Maximum repetition substring Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7578   Accepted: 2281 Description The repetition number of a string is defined as the maximum number R such that the string can be partitioned into R same conse

POJ 3693 Maximum repetition substring(后缀数组求最长重复子串)

题目大意:和spoj687类似,就是当长度相同是需要输出一个最小的字典序的序列. 解体思路:这次需要枚举所有的从i到d = i-L/i (d = i-L%i)的位置,然后记录保证最大值的同时,求出来字典序最小的. Maximum repetition substring Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7418   Accepted: 2217 Description The repetition numb

POJ - 3693 Maximum repetition substring(后缀数组求重复次数最多的连续重复子串)

Description The repetition number of a string is defined as the maximum number R such that the string can be partitioned into R same consecutive substrings. For example, the repetition number of "ababab" is 3 and "ababa" is 1. Given a

POJ 3693 Maximum repetition substring ——后缀数组

重复次数最多的字串,我们可以枚举循环节的长度. 然后正反两次LCP,然后发现如果长度%L有剩余的情况时,答案是在一个区间内的. 所以需要找到区间内最小的rk值. 两个后缀数组,四个ST表,$\Theta(n\log n)$ 就可以解决了 空间卡死了,瞎晶胞卡过去了. #include <map> #include <cmath> #include <queue> #include <cstdio> #include <cstring> #incl

POJ - 3693 Maximum repetition substring 后缀数组+RMQ

http://poj.org/problem?id=3693 整体思路就是枚举长度L,看长度为L的字符串在s中连续出现了几次. 既然长度为L的串是重复出现的,那么s[0]-s[L]-s[2*L]-中相邻的两个一定出现在重复的L串中.(并不一定在首尾位置,也可能出现在中间). 那么我们求i*L和(i+1)*L的LCP,假设答案为M,那么答案应该是M/L+1(加一是因为i*L~(i+1)*L也是答案). 但是这个答案不一定是最优,举一个下面的例子. 此时M/L+1是3,而正确答案是4.为什么呢?是因