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;
    }
    
  • 相关阅读:
    Java实现 LeetCode 394 字符串解码
    Java实现 LeetCode 394 字符串解码
    Java实现 LeetCode 392 判断子序列
    Java实现 LeetCode 392 判断子序列
    Java实现 LeetCode 392 判断子序列
    Java实现 LeetCode 391 完美矩形
    Java实现 LeetCode 391 完美矩形
    Java实现 LeetCode 391 完美矩形
    Java实现 LeetCode 390 消除游戏
    Java实现 LeetCode 390 消除游戏
  • 原文地址:https://www.cnblogs.com/AH2002/p/10223659.html
Copyright © 2011-2022 走看看