• 【bzoj3998】 TJOI2015—弦论


    http://www.lydsy.com/JudgeOnline/problem.php?id=3998 (题目链接)

    题意

      给出一个字符串,求它的字典序第K小的子串是什么,分情况讨论不在同一位置的相同子串需不需要重复考虑。

    Solution

      对于不需要重复考虑的情况,直接就是spoj上的那道例题,而需要重复考虑的情况不过就是预处理sum的时候每次加上的是当前节点的right集合大小。

    代码

    // bzoj3998
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<vector>
    #include<cstdio>
    #include<cmath>
    #include<set>
    #define LL long long
    #define inf 1<<30
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
     
    const int maxn=500010;
    int n,T,K;
    char s[maxn],ans[maxn];
    
    namespace SAM {
    	int last,Dargen,sz,n;
    	int len[maxn<<1],ch[maxn<<1][26],par[maxn<<1];
    	int b[maxn],id[maxn<<1],sum[maxn<<1],r[maxn<<1];
    	void Extend(int c) {
    		int np=++sz,p=last;last=np;
    		len[np]=len[p]+1;
    		for (;p && !ch[p][c];p=par[p]) ch[p][c]=np;
    		if (!p) par[np]=Dargen;
    		else {
    			int q=ch[p][c];
    			if (len[q]==len[p]+1) par[np]=q;
    			else {
    				int nq=++sz;len[nq]=len[p]+1;
    				memcpy(ch[nq],ch[q],sizeof(ch[q]));
    				par[nq]=par[q];
    				par[np]=par[q]=nq;
    				for (;p && ch[p][c]==q;p=par[p]) ch[p][c]=nq;
    			}
    		}
    	}
    	void build() {
    		last=Dargen=sz=1;
    		n=strlen(s+1);
    		for (int i=1;i<=n;i++) Extend(s[i]-'a');
    	}
    	void pre() {
    		for (int i=1;i<=sz;i++) b[len[i]]++;
    		for (int i=1;i<=n;i++) b[i]+=b[i-1];
    		for (int i=1;i<=sz;i++) id[b[len[i]]--]=i;
    		if (!T) {
    			for (int i=1;i<=sz;i++) r[i]=1;
    			for (int S=0,i=sz;i>=1;i--,S=0) {
    				for (int j=0;j<26;j++) if (ch[id[i]][j]) S+=sum[ch[id[i]][j]];
    				sum[id[i]]=S+1;
    			}
    		}
    		else {
    			for (int p=Dargen,i=1;i<=n;i++) p=ch[p][s[i]-'a'],r[p]++;
    			for (int i=sz;i>=1;i--) r[par[id[i]]]+=r[id[i]];
    			for (int S=0,i=sz;i>=1;i--,S=0) {
    				for (int j=0;j<26;j++) if (ch[id[i]][j]) S+=sum[ch[id[i]][j]];
    				sum[id[i]]=S+r[id[i]];
    			}
    		}
    	}
    	void query() {
    		int tot=0,p=Dargen;
    		while (K>0) {
    			for (int i=0;i<26;i++) if (ch[p][i]) {
    					if (sum[ch[p][i]]>=K) {
    						p=ch[p][i];K-=r[p];
    						ans[++tot]=i+'a';
    						break;
    					}
    					else K-=sum[ch[p][i]];
    				}
    		}
    		ans[++tot]='';
    	}	
    }
    using namespace SAM;
    
    int main() {
    	scanf("%s",s+1);
    	scanf("%d%d",&T,&K);
    	build();
    	pre();
    	query();
    	puts(ans+1);
    	return 0;
    }
    
  • 相关阅读:
    NS3之路---NS3Tutorial解读---Introduction & Resource
    NS3之路---在NS3中添加openflow模块
    NS3之路---代码编辑器VIM
    2019.9.5绘图
    2019.9.4拖拽事件
    2019.9.3视频播放
    2019.08.30数组去重的几种方法以及所需时间对比
    2019.08.29定时器以及轮播图
    2019.08.27BOM的六个子对象(2)
    2019.08.27BOM的六个子对象(1)
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6288756.html
Copyright © 2020-2023  润新知