【SPOJ】7258. Lexicographical Substring Search(后缀自动机)

http://www.spoj.com/problems/SUBLEX/

后缀自动机系列完成QAQ。。。撒花。。明天or今晚写个小结?

首先得知道:后缀自动机中,root出发到任意一个状态的路径对应一个子串,而且不重复。(原因似乎是逆序后缀树?

所以我们在自动机上预处理每一个状态的子串数目,然后从小到大枚举字符。

子串数目可以这样预处理出:s[x]=sum{s[y]}+1, y是x出发的下一个点,意思就是说,以x开头的子串有那么多个(即将孩子的所有子串前边都加上x),然后x单独算一个子串。

然后查找的时候从root出发(你可以这样想,因为root的right值包含了所有right,即root有所有后缀的r下标,所以只需要找最小的开头即可,然后转移后同理。

然后如果当前的转移的状态y,有s[y]>=k,那么说明子串在y的后缀里边,那么--k并且打印字符y后转移到y状态。(--k是因为我们转移的定义)

反之,如果s[y]<k, k-=s[y]

然后就行了。。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
#define rep(i, n) for(int i=0; i<(n); ++i)
#define for1(i,a,n) for(int i=(a);i<=(n);++i)
#define for2(i,a,n) for(int i=(a);i<(n);++i)
#define for3(i,a,n) for(int i=(a);i>=(n);--i)
#define for4(i,a,n) for(int i=(a);i>(n);--i)
#define CC(i,a) memset(i,a,sizeof(i))
#define read(a) a=getint()
#define print(a) printf("%d", a)
#define dbg(x) cout << (#x) << " = " << (x) << endl
#define error(x) (!(x)?puts("error"):0)
#define rdm(x, i) for(int i=ihead[x]; i; i=e[i].next)
inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<‘0‘||c>‘9‘; c=getchar()) if(c==‘-‘) k=-1; for(; c>=‘0‘&&c<=‘9‘; c=getchar()) r=r*10+c-‘0‘; return k*r; }

struct sam {
	static const int N=250005;
	int c[N][26], l[N], f[N], root, last, cnt, sz[N], o[N];
	sam() { cnt=0; root=last=++cnt; }
	void add(int x) {
		int now=last, a=++cnt; last=a;
		l[a]=l[now]+1;
		for(; now && !c[now][x]; now=f[now]) c[now][x]=a;
		if(!now) f[a]=root;
		else {
			int q=c[now][x];
			if(l[q]==l[now]+1) f[a]=q;
			else {
				int b=++cnt;
				memcpy(c[b], c[q], sizeof c[q]);
				l[b]=l[now]+1;
				f[b]=f[q];
				f[q]=f[a]=b;
				for(; now && c[now][x]==q; now=f[now]) c[now][x]=b;
			}
		}
	}
	void build(char *s) {
		int len=strlen(s);
		rep(i, len) add(s[i]-‘a‘);
		for1(i, 1, cnt) sz[l[i]]++;
		for1(i, 1, len) sz[i]+=sz[i-1];
		for1(i, 1, cnt) o[sz[l[i]]--]=i;
		for1(i, 0, len) sz[i]=0;
		for1(i, 1, cnt) sz[i]=1;
		for3(i, cnt, 1) {
			int p=o[i];
			rep(x, 26) sz[p]+=sz[c[p][x]];
		}
	}
	void getans(int k) {
		int now=root;
		while(k) {
			rep(x, 26) if(c[now][x]) {
				int y=c[now][x];
				if(sz[y]>=k) { putchar(‘a‘+x); --k; now=y; break; }
				else k-=sz[y];
			}
		}
		puts("");
	}
}a;

const int N=150005;
char s[N];
int main() {
	scanf("%s", s);
	a.build(s);
	int q=getint();
	while(q--) a.getans(getint());
	return 0;
}

  



Little Daniel loves to play with strings! He always finds different ways to have fun with strings! Knowing that, his friend Kinan decided to test his skills so he gave him a string S and asked him Qquestions of the form:

If all distinct substrings of string S were sorted lexicographically, which one will be the K-thsmallest?

After knowing the huge number of questions Kinan will ask, Daniel figured out that he can‘t do this alone. Daniel, of course, knows your exceptional programming skills, so he asked you to write him a program which given S will answer Kinan‘s questions.

Example:

S = "aaa" (without quotes)
substrings of S are "a" , "a" , "a" , "aa" , "aa" , "aaa". The sorted list of substrings will be:
"a", "aa", "aaa".

Input

In the first line there is Kinan‘s string S (with length no more than 90000 characters). It contains only small letters of English alphabet. The second line contains a single integer Q (Q <= 500) , the number of questions Daniel will be asked. In the next Q lines a single integer K is given (0 < K < 2^31).

Output

Output consists of Q lines, the i-th contains a string which is the answer to the i-th asked question.

Example

Input:aaa223

Output:
aaaaa
时间: 2024-11-06 14:43:09

【SPOJ】7258. Lexicographical Substring Search(后缀自动机)的相关文章

SPOJ 7258 Lexicographical Substring Search(后缀自动机)

[题目链接] http://www.spoj.com/problems/SUBLEX/ [题目大意] 给出一个字符串,求其字典序排名第k的子串 [题解] 求出sam上每个节点被经过的次数,然后采用权值线段树上查找第k大数类似的方法, 每次确定查找范围,进入相应的子树,同时输出路径上的点即可. [代码] #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const

SPOJ SUBLEX Lexicographical Substring Search - 后缀数组

题目传送门 传送门I 传送门II 题目大意 给定一个字符串,多次询问它的第$k$大本质不同的子串,输出它. 考虑后缀Trie.依次考虑每个后缀新增的本质不同的子串个数,显然,它是$n - sa[i] - height[i]$. 求出$height$数组后,求一求本质不同的子串个数的前缀和,可以对每个询问二分. 这里可以直接离线,$O(n + m)$扫一扫就好了. Code 1 /** 2 * SPOJ 3 * Problem#SUBLEX 4 * Accepted 5 * Time: 30ms

SPOJ SUBLEX 7258. Lexicographical Substring Search

看起来像是普通的SAM+dfs...但SPOJ太慢了......倒腾了一个晚上不是WA 就是RE ..... 最后换SA写了...... Lexicographical Substring Search Time Limit: 1000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu [Submit]   [Go Back]   [Status] Description Little Daniel loves to play wi

SPOJ SUBLEX - Lexicographical Substring Search

SUBLEX - Lexicographical Substring Search no tags Little Daniel loves to play with strings! He always finds different ways to have fun with strings! Knowing that, his friend Kinan decided to test his skills so he gave him a string S and asked him Q q

【SPOJ】Longest Common Substring(后缀自动机)

[SPOJ]Longest Common Substring(后缀自动机) 题面 Vjudge 题意:求两个串的最长公共子串 题解 \(SA\)的做法很简单 不再赘述 对于一个串构建\(SAM\) 另外一个串在\(SAM\)上不断匹配 最后计算答案就好了 匹配方法: 如果\(trans(s,c)\)存在 直接沿着\(trans\)走就行,同时\(cnt++\) 否则沿着\(parent\)往上跳 如果存在\(trans(now,c),cnt=now.longest+1\) 否则,如果不存在可行的

spoj1811 Longest Common Substring,后缀自动机

spoj1811LCS 问两个字符串最长公共子串. 做法很简单.匹配成功,则tl++,失败,从父指针回退,tl=t[now].len. 从这题可以清楚了解后缀自动机fa指针的性质: 指向一个状态,这个状态的接受串s[x..x+i]是与当前状态的接受串后缀s[j-i..j]匹配是最长的一个. 这里是不是发现了一个和KMP很像的性质? KMP在失配时通过next数组回退,那么这个回退到的位置i是s[0..i]与当前串的后缀s[j-i..j]匹配最长的一个. 所以. 利用后缀自动机可以求解一个串的子串

【SPOJ】Distinct Substrings(后缀自动机)

[SPOJ]Distinct Substrings(后缀自动机) 题面 Vjudge 题意:求一个串的不同子串的数量 题解 对于这个串构建后缀自动机之后 我们知道每个串出现的次数就是\(right/endpos\)集合的大小 但是实际上我们没有任何必要减去不合法的数量 我们只需要累加每个节点表示的合法子串的数量即可 这个值等于\(longest-shortest+1=longest-parent.longest\) #include<iostream> #include<cstdio&g

【BZOJ2555】SubString(后缀自动机,Link-Cut Tree)

[BZOJ2555]SubString(后缀自动机,Link-Cut Tree) 题面 BZOJ 题解 这题看起来不难 每次要求的就是\(right/endpos\)集合的大小 所以搞一个\(LCT\)维护一下\(SAM\)的\(Parent\)树就好了 但是代码一点都不好写(我还是对着黄学长的调的...) 于是乎我也学着魔改了一下\(LCT\) #include<iostream> #include<cstdio> #include<cstdlib> #include

Lexicographical Substring Search SPOJ - SUBLEX (后缀自动机)

Lexicographical Substrings Search \[ Time Limit: 149 ms \quad Memory Limit: 1572864 kB \] 题意 给出一个字符串,求出这个字符串上字典序第 \(k\) 小的子串. 思路 先对给出的字符串构建后缀自动机,因为后缀自动机上从根节点走到任意节点都是原串的一个子串,所以我们可以 \(dfs\) 求出节点 \(i\) 往后存在多少个子串. 对于查询第 \(k\) 小的子串时,在用一个 \(dfs\) 来求,对于当前节点