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

    弦论

    对于一个给定长度为 (N) 的字符串,求它的第 (K) 小子串。

    (T)0 则表示不同位置的相同子串算作一个。(T)1 则表示不同位置的相同子串算作多个。

    (N leq 5 imes 10^5, T<2, K leq 10^9)

    分析

    首先建立SAM,不同字符串对应于不同的从初始节点开始的路径,然后根据题意分类:

    1. t为0则表示不同位置的相同子串算作一个,那么每个状态对应路径的字符串的出现次数只能算作1次。
    2. t为1则表示不同位置的相同子串算作多个,那么每个状态对应路径的字符串的出现次数等于它的end-pos集合大小,基数排序求拓扑序后更新即可。

    时间复杂度(O(|S|))

    代码

    把初始节点设成1,即让last=tot=1会方便许多。

    #include<bits/stdc++.h>
    #define rg register
    #define il inline
    #define co const
    template<class T>il T read(){
        rg T data=0,w=1;rg char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') w=-1;ch=getchar();}
        while(isdigit(ch)) data=data*10+ch-'0',ch=getchar();
        return data*w;
    }
    template<class T>il T read(rg T&x) {return x=read<T>();}
    typedef long long ll;
    using namespace std;
    
    co int N=5e5+5;
    char s[N];
    int n,t,k;
    int ch[N*2][26],len[N*2],fa[N*2],siz[N*2],last=1,tot=1;
    void extend(int c){
    	int cur=++tot;
    	len[cur]=len[last]+1,siz[cur]=1;
    	int p=last;last=cur;
    	for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=cur;
    	if(!p) fa[cur]=1;
    	else{
    		int q=ch[p][c];
    		if(len[q]==len[p]+1) fa[cur]=q;
    		else{
    			int clone=++tot;
    			len[clone]=len[p]+1,copy(ch[q],ch[q]+26,ch[clone]);
    			fa[clone]=fa[q],fa[q]=fa[cur]=clone;
    			for(;ch[p][c]==q;p=fa[p]) ch[p][c]=clone;
    		}
    	}
    }
    int c[N],a[N*2],sum[N*2];
    int main(){
    	scanf("%s",s+1),n=strlen(s+1);
    	read(t),read(k);
    	for(int i=1;i<=n;++i) extend(s[i]-'a');
    	for(int i=1;i<=tot;++i) ++c[len[i]];
    	for(int i=1;i<=n;++i) c[i]+=c[i-1];
    	for(int i=1;i<=tot;++i) a[c[len[i]]--]=i;
    	for(int i=tot;i;--i){
    		if(t) siz[fa[a[i]]]+=siz[a[i]];
    		else siz[a[i]]=1;
    	}
    	siz[1]=0;
    	for(int i=tot;i;--i){
    		sum[a[i]]=siz[a[i]];
    		for(int c=0;c<26;++c)
    			if(ch[a[i]][c]) sum[a[i]]+=sum[ch[a[i]][c]];
    	}
    	if(k>sum[1]) return puts("-1"),0;
    	int now=1;k-=siz[now];
    	while(k){
    		int c=0;
    		for(;k>sum[ch[now][c]];++c) k-=sum[ch[now][c]];
    		putchar('a'+c);
    		now=ch[now][c],k-=siz[now];
    	}
    	return 0;
    }
    
  • 相关阅读:
    springAOP源码分析之篇三:代理对象的执行
    springAOP源码分析之篇二:代理对象的生成
    css样式float造成的浮动“塌陷”问题的解决办法
    css font的简写规则
    CSS学习
    工具
    用过的库
    The requested URL ***** was not found on this serve
    修改DeDe标签Pagelist分页样式
    DedeCms autoindex和itemindex使用介绍
  • 原文地址:https://www.cnblogs.com/autoint/p/10678352.html
Copyright © 2011-2022 走看看