洛谷P3975 [TJOI2015]弦論 (後綴自動機sam求第k小子串)

題目描述

爲了提高智商,ZJY開始學習弦論。這一天,她在《 String theory》中看到了這樣一道問題:對於一個給定的長度爲n的字符串,求出它的第k小子串是什麼。你能幫幫她嗎?

輸入格式

第一行是一個僅由小寫英文字母構成的字符串s

第二行爲兩個整數t和k,t爲0則表示不同位置的相同子串算作一個,t爲1則表示不同位置的相同子串算作多個。k的意義見題目描述。

輸出格式

輸出數據僅有一行,該行有一個字符串,爲第k小的子串。若子串數目不足k個,則輸出-1。

學習了後綴自動機 也終於A了這道感覺很麻煩的題= = 寫個博客慶祝一下

求第k小串的套路就像是在主席樹上面查詢第k小數,首先用後綴自動機處理出每個節點後續的子串的個數,然後對於每個節點枚舉26條邊轉移即可 一個節點所表示的串的出現次數即爲endpos集合的size,若對於t = 1相同子串不同位置算不同子串(除複製節點外,其他節點初始|endpos|大小設置爲1) 需要在後綴樹上面拓撲dp t = 0的話 每個節點只表示它的最長串 所以每個節點的值爲1 

 

#include<bits/stdc++.h>
using namespace std;
#pragma GCC optimize(2)
#define Sheryang main
typedef long long ll;
#define HEAP(...) priority_queue<__VA_ARGS__ >
#define heap(...) priority_queue<__VA_ARGS__,vector<__VA_ARGS__ >,greater<__VA_ARGS__ > >
template<class T> inline T min(T &x,const T &y){return x>y?y:x;}
template<class T> inline T max(T &x,const T &y){return x<y?y:x;}
//#define getchar()(p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
//char buf[(1 << 21) + 1], *p1 = buf, *p2 = buf;
ll read(){ll c = getchar(),Nig = 1,x = 0;while(!isdigit(c) && c!='-')c = getchar();if(c == '-')Nig = -1,c = getchar();while(isdigit(c))x = ((x<<1) + (x<<3)) + (c^'0'),c = getchar();return Nig*x;}
#define read read()
const int maxn = 1e6+7;
const int mod = 1e9+7;
/** keep hungry and keep calm! **/

int nxt[maxn],head[maxn],to[maxn],cnt; 
void add(int u,int v){
	nxt[++cnt] = head[u];
	head[u] = cnt;
	to[cnt] = v;
}

struct Sam{
	int trans[maxn][26],fail[maxn];
	int maxlen[maxn],minlen[maxn];
	int sz,last,vis[maxn];
	ll sum[maxn],num[maxn];
	Sam(){
		sz = last = 1;
	}
	void ins(int id){
		int cur = ++sz,p = last;
		num[cur] = 1;
		maxlen[cur] = maxlen[last] + 1;
		while(p && trans[p][id] == 0){
			trans[p][id] = cur;
			p = fail[p];
		}
		if(p == 0){
			fail[cur] = 1;
		}else{
			int q = trans[p][id];
			if(maxlen[q] == maxlen[p] + 1){
				fail[cur] = q;
			}else{
				int clone = ++sz;
				memcpy(trans[clone],trans[q],sizeof trans[q]);
				fail[clone] = fail[q];
				fail[cur] = fail[q] = clone;
				maxlen[clone] = maxlen[p] + 1;
				while(trans[p][id] == q){
					trans[p][id] = clone;
					p = fail[p];
				}
			}
		}
		last = cur;
	}
	void init(){
		for(int i=1;i<=sz;i++) head[i] = -1;
		for(int i=2;i<=sz;i++){
			add(fail[i],i);
		}
	}
	void dfs(int u){
		for(int i=head[u];~i;i = nxt[i]){
			dfs(to[i]);
			num[u] += num[to[i]];
		}
	}
	void calc(int u){
		sum[u] = num[u];
		vis[u] = 1;
		for(int i=0;i<26;i++){
			int v = trans[u][i];
			if(v != 0){
				if(vis[v] == 0)calc(v);
				sum[u] += sum[v];
			}
		}
	}
	void Fuck(int u,int k){
		int rt = 1;
		while(k){
			for(int i=0;i<26;i++){
				int v = trans[rt][i];
				if(v != 0){
					if(k <= sum[v]){
						putchar('a' + i);
						k -= num[v];
						rt = v;
						break;
					}else{
						k -= sum[v];
					}
				}
			}
		}
	}
	void Solve(){
		int op = read , k = read;
		init();
		if(op == 1){
			dfs(1);
		}else{
			for(int i=1;i<=sz;i++) num[i] = 1;
		}
		num[1] = 0; 
		calc(1);
		if(k > sum[1]){
			printf("-1");
		}else{
			Fuck(1,k);
		}
		puts("");
	}
}Sam;

char s[maxn];
int Sheryang(){
	scanf("%s",s);
	for(int i=0;s[i];i++){
		Sam.ins(s[i]-'a');
	}
	Sam.Solve();
	return 0; 
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章