zoukankan      html  css  js  c++  java
  • SP7258 SUBLEX

    传送门

    解题思路

      首先建(sam),然后在拓扑序上(dp)一下,把每个点的路径数算出来,然后统计答案时就在自动机上(dfs)一下,仿照平衡树那样找第(k)小。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    
    using namespace std;
    const int MAXN = 90005;
    
    inline int rd(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
    	while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    	return f?x:-x;
    }
    
    int n,Q,l[MAXN<<1],fa[MAXN<<1],ch[MAXN<<1][27];
    int lst,cnt,f[MAXN<<1],c[MAXN<<1],a[MAXN<<1];
    char s[MAXN];
    
    inline void Insert(int c){
    	int p=lst,np=++cnt;lst=np;l[np]=l[p]+1;
    	for(;p && !ch[p][c];p=fa[p]) ch[p][c]=np;
    	if(!p) fa[np]=1;
    	else {
    		int q=ch[p][c];
    		if(l[q]==l[p]+1) fa[np]=q;
    		else{
    			int nq=++cnt;l[nq]=l[p]+1;
    			memcpy(ch[nq],ch[q],sizeof(ch[q]));
    			fa[nq]=fa[q];fa[q]=fa[np]=nq;
    			for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
    		}
    	}
    } 
    
    void query(int x){
    	int p=1;
    	while(x){
    		for(int i=1;i<=26;i++)if(ch[p][i]){
    			if(f[ch[p][i]]<x)  x-=f[ch[p][i]];
    			else {p=ch[p][i];putchar('a'+i-1);x--;break;}	
    		}
    	}
    	putchar('
    ');
    }
    
    int main(){
    	scanf("%s",s+1);n=strlen(s+1);lst=cnt=1;
    	for(int i=1;i<=n;i++) Insert(s[i]-'a'+1);
    	for(int i=1;i<=cnt;i++) c[l[i]]++;
    	for(int i=1;i<=cnt;i++) c[i]+=c[i-1];
    	for(int i=1;i<=cnt;i++) a[c[l[i]]--]=i;
    	for(int i=cnt;i;i--){
    		f[a[i]]=1;
    		for(int j=1;j<=26;j++)
    			f[a[i]]+=f[ch[a[i]][j]];
    	}
    	f[1]--;Q=rd();int x;
    	while(Q--){x=rd();query(x);}
    	return 0;
    } 
    
  • 相关阅读:
    今年的第几天?
    特殊乘法
    abc
    求最大最小数
    二叉树遍历
    球的半径和体积
    成绩排序
    OC学习篇之---类的定义
    OC学习篇之---第一个程序HelloWorld
    OC学习篇之---类的初始化方法和点语法的使用
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/10106145.html
Copyright © 2011-2022 走看看