• [SP7258 SUBLEX]Lexicographical Substring Search


    luogu

    题意

    给一个串,求其第k小子串。
    不同位置出现的内容相同的子串算作同一个子串。
    有多组询问。
    (nle9*10^4,Tle500)

    sol

    建出SAM后跑一遍基数排序,预处理出每个状态可以转移到的子串个数。
    然后就变成了一个比较经典的第(k)小问题:假设当前面临状态(now),若(now)可以转移到的数量大于等于(k),那就说明第(k)小一定是(now)的后继状态。直接进入(now)状态。
    否则,令(k=k-sz[now]),然后跳过状态(now),考虑下一个状态。

    code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int N = 2e5+5;
    int n,last=1,tot=1,tr[N][26],fa[N],len[N],t[N],a[N],sz[N],Q,k;
    char s[N];
    void extend(int c)
    {
    	int v=last,u=++tot;last=u;
    	len[u]=len[v]+1;
    	while (v&&!tr[v][c]) tr[v][c]=u,v=fa[v];
    	if (!v) fa[u]=1;
    	else
    	{
    		int x=tr[v][c];
    		if (len[x]==len[v]+1) fa[u]=x;
    		else
    		{
    			int y=++tot;
    			memcpy(tr[y],tr[x],sizeof(tr[y]));
    			fa[y]=fa[x];fa[x]=fa[u]=y;len[y]=len[v]+1;
    			while (v&&tr[v][c]==x) tr[v][c]=y,v=fa[v];
    		}
    	}
    }
    int main()
    {
    	scanf("%s",s+1);n=strlen(s+1);
    	for (int i=1;i<=n;++i) extend(s[i]-'a');
    	for (int i=1;i<=tot;++i) ++t[len[i]];
    	for (int i=1;i<=tot;++i) t[i]+=t[i-1];
    	for (int i=1;i<=tot;++i) a[t[len[i]]--]=i;
    	for (int i=tot;i;--i)
    	{
    		sz[a[i]]=1;
    		for (int j=0;j<26;++j) sz[a[i]]+=sz[tr[a[i]][j]];
    	}
    	scanf("%d",&Q);
    	while (Q--)
    	{
    		scanf("%d",&k);int now=1;
    		while (k>0)
    			for (int j=0;j<26;++j)
    				if (tr[now][j])
    					if (sz[tr[now][j]]>=k)
    					{
    						putchar(j+'a');
    						--k;now=tr[now][j];
    						break;
    					}
    					else k-=sz[tr[now][j]];
    		puts("");
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    。。。。。。
    数据库
    python基础
    。。。。
    drf
    CRM笔记梳理
    人生苦短,我学PYTHON
    React的初步了解
    递归与迭代比较
    有没有大佬会很标准的三层架构
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8660406.html
Copyright © 2020-2023  润新知