P3975 [TJOI2015]弦论

题目描述

为了提高智商,ZJY开始学习弦论。这一天,她在《 String theory》中看到了这样一道问题:对于一个给定的长度为n的字符串,求出它的第k小子串是什么。你能帮帮她吗?

输入格式

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

第二行为两个整数t和k,t为0则表示不同位置的相同子串算作一个,t为1则表示不同位置的相同子串算作多个。k的意义见题目描述。

输出格式

输出数据仅有一行,该行有一个字符串,为第k小的子串。若子串数目不足k个,则输出-1。

输入输出样例

输入 #1

aabc
0 3

输出 #1

aab

输入 #2

aabc
1 3

输出 #2

aa

输入 #3

aabc
1 11

输出 #3

-1

说明/提示

数据范围

对于10%的数据,n ≤ 1000。

对于50%的数据,t = 0。

对于100%的数据,n ≤ 5 × 10^5, t < 2, k ≤ 10^9。

其实我对sam还不是很透彻只是似懂非懂

只放代码吧

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 2e6+5; // 两倍空间 , 一次插入可能产生两个节点
int n , tot = 1 , las = 1;
int len[N] , fa[N] , tr[N][26] , a[N] , t[N];
long long siz[N] , sum[N];
char c[N];

void Insert(int c) // 板子又一次出锅
{
	int cur = ++tot , p = las; len[cur] = len[las] + 1; las = cur; siz[cur] = 1;
	for( ; p && tr[p][c] == 0 ; p = fa[p]) tr[p][c] = cur;
	if(p == 0) fa[cur] = 1;
	else
	{
		int q = tr[p][c];
		if(len[q] == len[p] + 1) fa[cur] = q;
		else
		{// 这里的nq的siz不能设为 1
			int nq = ++tot;/*siz[tot] = 1;*/ fa[nq] = fa[q]; len[nq] = len[p] + 1;
			for(int i = 0 ; i < 26 ; ++i) tr[nq][i] = tr[q][i];
			fa[cur] = fa[q] = nq;
			for( ; p && tr[p][c] == q ; p = fa[p]) tr[p][c] = nq;
		}
	}
}

int main()
{
	scanf("%s",c+1); n = strlen(c+1);
	int T , K; scanf("%d %d" , &T , &K);
	for(int i = 1 ; i <= n ; ++i) Insert(c[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;
	// tr 与 fa 并不是一个东西 , 
	// tr 表示在这个状态后加上 i 会到达的状态 , 
	// fa 是后缀中第一个endpos不同于它本身的后缀的状态
	for(int i = tot ; i >= 1 ; --i) 
	{
		int x = a[i];
		if(T == 1) siz[fa[x]] += siz[x];
		else siz[x] = 1;
	}
	siz[1] = 0;
	for(int i = tot ; i >= 1 ; --i)
	{
		int x = a[i]; sum[x] = siz[x];
		for(int j = 0 ; j < 26 ; ++j)
			if(tr[x][j]) sum[x] += sum[tr[x][j]];
	}
	if(sum[1] < K) puts("-1");
	else
	{
		int now = 1; K -= siz[now];
		while(K > 0)
		{
			int i = 0;
			while(K > sum[tr[now][i]])
			{
				K -= sum[tr[now][i]];
				i++;
			}
			now = tr[now][i]; putchar(i + 'a');
			K -= siz[now];
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/R-Q-R-Q/p/12150381.html