zoukankan      html  css  js  c++  java
  • cogs 2605 寒假ing

    题目链接
    题解:
    其实这道题是poj3693的弱化版,不用考虑字符串的字典序。
    博客链接
    还是先枚举循环节长度T,再枚举i,保证iT,(i+1)T下标合法。对于这两个下标求a=LCP(iT,(i+1)T)。因为不用考虑字符串是谁,只需要知道循环节个数最大值即可,因此是有更简单的做法的,即不需要求iT,(i+1)T的LCS。
    简单地说,如果(T|a),此时iT前面即使还能匹配上也不可能再多一个循环节,否则这个子串就是由(i-1)T,iT访问的了。所以直接用(lfloorfrac{a}{T} floor+1)更新答案即可。如果不整除,那么可能在前面多匹配些,会多一个循环节,那就再求一下(b=LCP(iT-l+amod l,(i+1)T-l+amod l)),用(lfloorfrac{b}{T} floor+1)更新一下答案,复杂度(O(nln n))

    code

    #include<stdio.h>
    #include<string.h>
    #include<iostream>
    using namespace std;
    #define fcl fclose(stdin); fclose(stdout); return 0
    int n;
    char str[100010];
    int C[100010],Ws[100010],Rank[100010],Sa[100010],Height[100010],ST[50010][19];
    int Table[50010];
    void Da(){
    	int i,j,c,k,m=200,p;
    	memset(Ws,0,(m+1)<<2);
    	for(i=0;i<n;++i) Ws[Rank[i]=str[i]]++;
    	for(i=1;i<=m;++i) Ws[i]+=Ws[i-1];
    	for(i=0;i<n;++i) Sa[--Ws[Rank[i]]]=i;
    	for(c=1;c<=n;c<<=1,m=p){
    		for(j=0,i=n-c;i<n;++i) C[j++]=i;
    		for(i=0;i<n;++i) if(Sa[i]>=c) C[j++]=Sa[i]-c;
    		memset(Ws,0,(m+1)<<2);
    		for(i=0;i<n;++i) Ws[Rank[i]]++;
    		for(i=1;i<=m;++i) Ws[i]+=Ws[i-1];
    		for(i=n-1;i>=0;--i) Sa[--Ws[Rank[C[i]]]]=C[i];
    		for(C[Sa[0]]=0,i=1,p=0;i<n;++i)
    			C[Sa[i]]=(Rank[Sa[i]]==Rank[Sa[i-1]]&&Rank[Sa[i]+c]==Rank[Sa[i-1]+c]?p:++p);
    		memcpy(Rank,C,n<<2);
    	}
    	for(i=0,j=0,k=0;i<n;++i){
    		if(Rank[i]==0) continue;
    		for(k=(k?k-1:0),j=Sa[Rank[i]-1];str[i+k]==str[j+k];++k);
    		Height[Rank[i]]=k;
    	}
    	for(i=n-1;i>=0;--i){
    		ST[i][0]=Height[i];
    		for(j=0;j<17;++j){
    			if(i+(1<<j)<n) ST[i][j+1]=min(ST[i][j],ST[i+(1<<j)][j]);
    			else ST[i][j+1]=ST[i][j];
    		}
    	}
    }
    inline int Lcp(int a,int b){
    	a=Rank[a]; b=Rank[b];
    	if(a>b) swap(a,b);
    	a++;
    	return min(ST[a][Table[b-a+1]],ST[b-(1<<Table[b-a+1])+1][Table[b-a+1]]);
    }
    int main(){
    	freopen("broken.in","r",stdin);
    	freopen("broken.out","w",stdout);
    	
    	int T;
    	for(int i=1,k=0;i<=50000;i<<=1,++k){
    		for(int j=i;j<(i<<1)&&j<=50000;++j) Table[j]=k;
    	}
    	scanf("%d",&T);
    	while(T--){
    		scanf("%d",&n);
    		scanf("%s",str);
    		str[n++]='$'; str[n]=0;
    		Da();
    		int l,i,x,y,ans=1;
    		for(l=1;(l<<1)<=n;++l){
    			for(i=0;i+l<n;i+=l*(y/l+1)){
    				x=i+l;
    				y=Lcp(i,x);
    				ans=max(ans,y/l+1);
    				if(y%l) ans=max(ans,1+Lcp(i-l+y%l,x-l+y%l)/l);
    			}
    		}
    		printf("%d
    ",ans);
    	}
    	fcl;
    }
    
  • 相关阅读:
    子类父类拥有同名的方法时……
    大道至简第六章阅读感想
    大道至简第五章阅读感想
    java中子类与基类变量间的赋值
    继承与接口的使用
    产生10个随机数求和及一些产生随机数相关知识
    【文件处理】xml 文件 SAX解析
    【文件处理】xml 文件 DOM解析
    【文件处理】RandomAccessFile
    【Directory】文件操作(初识文件操作二)
  • 原文地址:https://www.cnblogs.com/kito/p/7111437.html
Copyright © 2011-2022 走看看