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

    Description

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

    Input

    第一行是一个仅由小写英文字母构成的字符串S

    第二行为两个整数T和K,T为0则表示不同位置的相同子串算作一个。T=1则表示不同位置的相同子串算作多个。K的意义如题所述。

    Output

    输出仅一行,为一个数字串,为第K小的子串。如果子串数目不足K个,则输出-1

    Sample Input

    aabc
    0 3
    

    Sample Output

    aab
    

    Solution

    后缀自动机模板题。

    先建出后缀自动机,预处理出(sum[i])表示从自动机上的(i)点出发可以得到多少个串。

    要预处理这个,先要预处理出(sz[i])表示自动机上第(i)个点代表的(endpos)集合的大小。

    对于(T=0),直接每个(sz[i]=1)就行了,否则就在(parent)树上递推就好了。

    然后得到这个就可以在自动机上递推(sum[i])了。

    tips:后缀自动机的(toposort)可以按(maxl)进行桶排得到。

    #include<bits/stdc++.h>
    using namespace std;
     
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
     
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
    
    const int maxn = 1e6+10;
    
    char s[maxn];
    int qs=1,cnt=1,lstp=1,n,T,rk;
    int tr[maxn][27],par[maxn],ml[maxn],sz[maxn],r[maxn],t[maxn],sum[maxn];
    
    void append(int c) {
    	int p=lstp,np=++cnt;ml[np]=ml[p]+1;lstp=np;sz[np]=1;
    	for(;p&&tr[p][c]==0;p=par[p]) tr[p][c]=np;
    	if(!p) return par[np]=qs,void();
    	int q=tr[p][c];
    	if(ml[p]+1<ml[q]) {
    		int nq=++cnt;ml[nq]=ml[p]+1;
    		memcpy(tr[nq],tr[q],sizeof tr[nq]);
    		par[nq]=par[q],par[q]=par[np]=nq;
    		for(;p&&tr[p][c]==q;p=par[p]) tr[p][c]=nq;
    	}else par[np]=q;
    }
    
    void print(int x,int k) {
    	if(k>sz[x]) k-=sz[x];
    	else return ;
    	for(int i=1;i<=26;i++)
    		if(tr[x][i]) {
    			if(k>sum[tr[x][i]]) k-=sum[tr[x][i]];
    			else {
    				putchar(i+'a'-1);
    				print(tr[x][i],k);break;
    			}
    		}
    }
    
    int main() {
    	scanf("%s",s+1);n=strlen(s+1);
    	for(int i=1;i<=n;i++) append(s[i]-'a'+1);
    	
    	for(int i=1;i<=cnt;i++) t[ml[i]]++;
    	for(int i=1;i<=n;i++) t[i]+=t[i-1];
    	for(int i=1;i<=cnt;i++) r[t[ml[i]]--]=i;
    
    	read(T),read(rk);
    	for(int i=cnt;i;i--) T?sz[par[r[i]]]+=sz[r[i]]:sz[r[i]]=1;
    	sz[qs]=0;
    	for(int i=cnt;i;i--) {
    		sum[r[i]]=sz[r[i]];
    		for(int j=1;j<=26;j++) if(tr[r[i]][j]) sum[r[i]]+=sum[tr[r[i]][j]];
    	}
    	
    	if(sum[1]>=rk) print(1,rk),puts("");else puts("-1");
    	return 0;
    }
    
  • 相关阅读:
    JavaScript字符串和字符数组
    JavaScript数组&类数组转换
    JavaScript判断值是否是NaN
    JavaScript中七种数据类型·中·一
    QRcode.js 生成二维码
    你不知道的JavasScript上篇·第五章·原型·下
    你不知道的JavasScript上篇·第五章·原型·上
    你不知道的JavasScript上篇·第四章·混合对象·类
    你不知道的JavasScript上篇·第三章·对象
    Vue2.x之父子组件数据传递
  • 原文地址:https://www.cnblogs.com/hbyer/p/10433607.html
Copyright © 2011-2022 走看看