zoukankan      html  css  js  c++  java
  • [TJOI2015]弦论

    我们先求出该字符串的(SA)(Ht)

    然后分类讨论

    (T=0)时,每次去掉(Ht)往后扫就行

    (T=1)时,我们考虑(lcp)对答案的影响

    既然用到(lcp),那就要用(ST)表维护

    左端点固定时,随右端点的增大,区间(min)单调不升

    我们就可以用二分+限制右端点的方式统计某个后缀的前缀的贡献

    循环遍历每个后缀时,由于(Ht)部分已经统计过对答案的贡献,就不用再计算了,从(Ht+1)的位置继续向后统计即可

    #include"cstdio"
    #include"cstring"
    #include"iostream"
    #include"algorithm"
    using namespace std;
    
    const int MAXN=5e5+5;
    
    int ln,maxn,p,t;
    int SA[MAXN],id[MAXN],rnk[MAXN],bnk[MAXN],Ht[MAXN];
    char ch[MAXN];
    int ST[19][MAXN],lg[MAXN];
    
    void shel()
    {
    	for(int i=1;i<=ln;++i) ++bnk[rnk[id[i]]];
    	for(int i=1;i<=maxn;++i) bnk[i]+=bnk[i-1];
    	for(int i=1;i<=ln;++i) SA[++bnk[rnk[id[i]]-1]]=id[i];
    	for(int i=0;i<=maxn;++i) bnk[i]=0;
    	return;
    }
    
    void GetSA()
    {
    	for(int i=1;i<=ln;++i) rnk[i]=ch[i],id[i]=i,maxn=max(maxn,rnk[i]);
    	shel();
    	for(int k=1;k<ln;k<<=1){
    		for(int i=1;i<=k;++i) id[i]=ln-k+i;
    		int ct=k;
    		for(int i=1;i<=ln;++i) if(SA[i]>k) id[++ct]=SA[i]-k;
    		shel();swap(id,rnk);rnk[SA[1]]=1;
    		for(int i=2;i<=ln;++i) rnk[SA[i]]=(id[SA[i]]==id[SA[i-1]]&&id[SA[i]+k]==id[SA[i-1]+k])?rnk[SA[i-1]]:rnk[SA[i-1]]+1;
    		if(rnk[SA[ln]]==ln) return;
    		maxn=rnk[SA[ln]];
    	}return;
    }
    
    void GetHt()
    {
    	int k=0;
    	for(int i=1;i<=ln;++i){
    		if(rnk[i]==1) continue;
    		if(k) --k;
    		int ct=SA[rnk[i]-1];
    		while(ct+k<=ln&&i+k<=ln&&ch[i+k]==ch[ct+k]) ++k;
    		Ht[rnk[i]]=k;
    	}return;
    }
    
    int Getmi(int l,int r){int tmp=lg[r-l+1];return min(ST[tmp][l+(1<<tmp)-1],ST[tmp][r]);}
    
    void slv1()
    {
    	for(int i=1;i<=ln;++i) lg[i]=i>>lg[i-1]+1?lg[i-1]+1:lg[i-1];
    	for(int i=1;i<=ln;++i) ST[0][i]=Ht[i];
    	for(int j=1;j<=lg[ln];++j){
    		int tmp=1<<j-1;
    		for(int i=tmp<<1;i<=ln;++i){
    			ST[j][i]=min(ST[j-1][i],ST[j-1][i-tmp]);
    		}
    	}for(int i=1;i<=ln;++i){
    		int tmp=SA[i]+Ht[i];
    		int ct=ln;
    		while(1){
    			if(tmp>ln) break;
    			if(ct==i){
    				if(t>ln-tmp+1){t-=ln-tmp+1;break;}
    				for(int j=SA[i];j<=tmp+t-1;++j) putchar(ch[j]);
    				return;
    			}int l=i,r=ct;
    			while(l<r){
    				int mid=l+r+1>>1;
    				if(Getmi(i+1,mid)>=tmp-SA[i]+1) l=mid;
    				else r=mid-1;
    			}ct=r;
    			if(t>r-i+1) t-=r-i+1;
    			else{
    				for(int j=SA[i];j<=tmp;++j) putchar(ch[j]);
    				return;
    			}++tmp;
    		}
    	}puts("-1");
    	return;
    }
    
    void slv2()
    {
    	int ct=1;
    	while(t>ln-SA[ct]-Ht[ct]+1) t-=ln-SA[ct]-Ht[ct]+1,++ct;
    	if(ct>ln){puts("-1");return;}
    	for(int i=SA[ct];i<=SA[ct]+t+Ht[ct]-1;++i) putchar(ch[i]);
    	puts("");
    	return;
    }
    
    int main()
    {
    	scanf("%s",ch+1);ln=strlen(ch+1);
    	GetSA();GetHt();scanf("%d%d",&p,&t);
    	p?slv1():slv2();
    	return 0;
    }
    
  • 相关阅读:
    Codeforces 379 F. New Year Tree
    「NOI2018」屠龙勇士
    「NOI2018」归程
    深入理解Java枚举类型(enum)
    2018.6.9-学习笔记
    String、StringBuffer与StringBuilder介绍
    HashMap和HashTable到底哪不同?
    HashMap详解
    List,Set和Map详解及其区别和他们分别适用的场景
    Java中高级面试题(1)
  • 原文地址:https://www.cnblogs.com/AH2002/p/10223659.html
Copyright © 2011-2022 走看看