zoukankan      html  css  js  c++  java
  • POJ 3693 Maximum repetition substring ——后缀数组

    重复次数最多的字串,我们可以枚举循环节的长度。

    然后正反两次LCP,然后发现如果长度%L有剩余的情况时,答案是在一个区间内的。

    所以需要找到区间内最小的rk值。

    两个后缀数组,四个ST表,$Theta(nlog n)$

    就可以解决了

    空间卡死了,瞎晶胞卡过去了。

    #include <map>
    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define F(i,j,k) for (int i=j;i<=k;++i)
    #define D(i,j,k) for (int i=j;i>=k;--i)
    #define ll long long
    #define mp make_pair
    #define maxn 200010
    #define inf 0x3f3f3f3f
    
    int _log[maxn],kas=0;
    
    struct Suffix_Array{
    	int s[maxn];
    	int cnt[maxn],sa[maxn],tmp[maxn],rk[maxn],h[maxn];
    	int st[2][maxn][18]; 
    	void build(int n,int m)
    	{
    		s[n]=0; n++; int i,j,k;
    		F(i,0,n+2) sa[i]=tmp[i]=rk[i]=h[i]=0;
    		F(i,0,m-1) cnt[i]=0;
    		F(i,0,n-1) cnt[rk[i]=s[i]]++;
    		F(i,1,m-1) cnt[i]+=cnt[i-1];
    		F(i,0,n-1) sa[--cnt[rk[i]]]=i;
    		for (k=1;k<=n;k<<=1)
    		{
    			F(i,0,n-1)
    			{
    				int j=sa[i]-k;
    				if (j<0) j+=n;
    				tmp[cnt[rk[j]]++]=j;
    			}
    			sa[tmp[cnt[0]=0]]=j=0;
    			F(i,1,n-1)
    			{
    				if (rk[tmp[i]]!=rk[tmp[i-1]]||rk[tmp[i]+k]!=rk[tmp[i-1]+k]) cnt[++j]=i;
    				sa[tmp[i]]=j;
    			}
    			memcpy(rk,sa,n*sizeof(int));
    			memcpy(sa,tmp,n*sizeof(int));
    			if (j>=n-1) break;
    		}
    		for (int i=k=0;i<n;h[rk[i++]]=k)
    			for (k?k--:0,j=sa[rk[i]-1];s[i+k]==s[j+k];k++);
    		F(i,0,n-1) st[0][i][0]=h[i];
    		F(i,1,17) F(j,0,n-(1<<i)) st[0][j][i]=min(st[0][j][i-1],st[0][j+(1<<(i-1))][i-1]);
    		F(i,0,n-1) st[1][i][0]=rk[i];
    		F(i,1,17) F(j,0,n-(1<<i)) st[1][j][i]=min(st[1][j][i-1],st[1][j+(1<<(i-1))][i-1]);
    	}
    	int query(int id,int l,int r)
    	{
    		int k=_log[r-l+1];
    		return min(st[id][l][k],st[id][r-(1<<k)+1][k]);
    	}
    	int lcp(int a,int b)
    	{
    		int aa=rk[a],bb=rk[b];
    		return query(0,min(aa,bb)+1,max(aa,bb));
    	}
    }SA,SB;
    
    int ansl,ansr,mx,ans,n,minn;char s[maxn];
    
    void solve(int L)
    {
    	for (int i=0;i+L<n;i+=L)
    		if (s[i]==s[i+L])
    		{
    			int l=SA.lcp(i+1,i+L+1),r=SB.lcp(n-i-1,n-i-L-1);
    			if (l+r<L) continue;
    			if ((l+r)/L+1>mx) mx=(l+r)/L+1,ans=inf;
    			if ((l+r)/L+1==mx)
    			{
    				int tmp=SA.query(1,i-r+1,i-r+1+(l+r)%L);
    				if (tmp<ans)
    				{
    					ans=tmp;
    					ansl=SA.sa[tmp]; ansr=ansl+mx*L-1;
    				}
    			}
    		}
    }
    
    int main()
    {
    	F(i,2,maxn-1) _log[i]=_log[i>>1]+1;
    	while (scanf("%s",s)!=EOF&&s[0]!='#')
    	{
    		ansl=ansr=0,mx=0;minn=inf;
    		printf("Case %d: ",++kas);
    		mx=0;
    		n=strlen(s);
    		F(i,0,n-1)
    		{
    			SA.s[i]=s[i]-'a'+1;
    			SB.s[i]=s[n-i-1]-'a'+1;
    			minn=min(minn,(int)s[i]);
    		}
    		SA.s[n]=SB.s[n]=0;
    		SA.build(n,30); SB.build(n,30);
    		for (int i=1;i<=n;++i) solve(i);
    		if (mx==0) printf("%c
    ",minn);
    		else
    		{
    			F(i,ansl,ansr) printf("%c",s[i]);
    			printf("
    ");
    		}
    	}
    }
    

      

  • 相关阅读:
    c++作业2 9.22
    c++作业1 9.22
    c++练习题2
    c++练习题1
    10.10作业3
    10.10作业2
    10.10作业 1
    9.22作业5
    9.22作业4
    9.22zuo
  • 原文地址:https://www.cnblogs.com/SfailSth/p/6647569.html
Copyright © 2011-2022 走看看