列表

详情


NC207749. 子串排名

描述

给出一个字符串S,设长度为N,那么一共有个子串。

现在将这些子串按照字典序从小到大排序,依次连接成一个字符串T。

有Q次询问,每次询问T的第x个字符是什么。

输入描述

第一行一个字符串S。

第二行一个正整数Q。

之后Q行,每行一个正整数,表示询问的位置。

输出描述

输出一个字符串,表示每次询问的答案依次拼接形成的字符串。

示例1

输入:

aca
10
1 2 3 4 5 6 7 8 9 10

输出:

aaacacacca

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(clang++11) 解法, 执行用时: 815ms, 内存消耗: 310648K, 提交时间: 2020-11-28 20:03:08

#include<algorithm>
#include<cstring>
#include<cctype>
#include<cstdio>
#define rep(i,x,y) for(int i=x; i<=y; ++i)
#define repd(i,x,y) for(int i=x; i>=y; --i)
#define mid (l+r>>1)

using namespace std;
const int N=500005;
typedef long long LL;
char s[N];
LL n,m,x,tot,lst,trf[N<<1][26],len[N<<1],fa[N<<1],son[N<<1][26],vt[N<<1],bin[N],p[N<<1],rk[N<<1];
LL k,siz[N<<1],c[N<<1];

int ins(int c)
{
	int x=++tot,u=lst,v;
	lst=tot,len[x]=len[u]+1;
	for(; u && !trf[u][c]; trf[u][c]=x,u=fa[u]);
	if(!u) fa[x]=1;
	else if(len[u]+1==len[v=trf[u][c]]) fa[x]=v;
	else
	{
		int w=++tot;
		len[w]=len[u]+1,fa[w]=fa[v];
		memcpy(trf[w],trf[v],sizeof(trf[v]));
		for(fa[v]=fa[x]=w; u && trf[u][c]==v; trf[u][c]=w,u=fa[u]);
	}
	::c[x]=1;
	return x;
}

LL query(LL a,LL b)
{
	return (a+b)*(b-a+1)/2;
}

void dfs(int x)
{
	++tot;
	vt[tot]=x;
	siz[tot]=siz[tot-1]+c[x]*query(len[fa[x]]+1,len[x]);
	rep(i,0,25) if(son[x][i]) dfs(son[x][i]);
}

int main()
{
	scanf("%s",s+1),n=strlen(s+1);
	tot=lst=1;
	repd(i,n,1) p[ins(s[i]-'a')]=i;
	rep(i,1,tot) ++bin[len[i]];
	rep(i,1,n) bin[i]+=bin[i-1];
	rep(i,1,tot) rk[bin[len[i]]--]=i;
	repd(i,tot,2)
	{
		int x=rk[i];
		p[fa[x]]=p[x],c[fa[x]]+=c[x];
		int L=len[fa[x]];
		son[fa[x]][s[p[x]+L]-'a']=x;
	}
	tot=0;
	dfs(1);
	scanf("%d",&m);
	while(m--)
	{
		scanf("%lld",&k);
		int l=1,r=tot;
		while(l<=r)
			siz[mid]>=k?r=mid-1:l=mid+1;
		k-=siz[r],x=vt[r+1];
		int Lf=len[fa[x]],L=len[x];
		l=Lf+1,r=L;
		while(l<=r)
		{
			LL tmp=c[x]*query(l,mid);
			if(tmp<k) k-=tmp,l=mid+1;
			else r=mid-1;
		}
		k=(k-1)%l+1;
		putchar(s[p[x]+k-1]);
	}
	puts("");
	return 0;
}
	

上一题