1. 程式人生 > >BZOJ3998: [TJOI2015]弦論(字尾自動機)

BZOJ3998: [TJOI2015]弦論(字尾自動機)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int MAXN = 1e6 + 10;
inline int read() {
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '
0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * f; } char s[MAXN]; int opt, K, N; int fa[MAXN], len[MAXN], ch[MAXN][27], siz[MAXN], right[MAXN], tot = 1, last = 1, root = 1; void insert(int x) { int now = ++tot, pre = last; last = now; len[now] = len[pre] + 1; right[now]
= 1; for(; pre && !ch[pre][x]; pre = fa[pre]) ch[pre][x] = now; if(!pre) fa[now] = root; else { int q = ch[pre][x]; if(len[q] == len[pre] + 1) fa[now] = q; else { int nows = ++tot; len[nows] = len[pre] + 1; memcpy(ch[nows], ch[q],
sizeof(ch[q])); fa[nows] = fa[q]; fa[q] = fa[now] = nows; for(; pre && ch[pre][x] == q; pre = fa[pre]) ch[pre][x] = nows; } } } void Query(int K) { int now = root; if(K > siz[root]) return (void) printf("-1"); while(K) { if(now != root) K -= right[now]; if(K <= 0) break; for(int i = 0; i <= 25; i++) if(ch[now][i]) { if(siz[ch[now][i]] >= K) {putchar(i + 'a'); now = ch[now][i]; break; } else K -= siz[ch[now][i]]; } } puts(""); } void Topsort() { static int A[MAXN], a[MAXN]; for(int i = 1; i <= tot; i++) A[len[i]]++; for(int i = 1; i <= N; i++) A[i] += A[i - 1]; for(int i = tot; i >= 1; i--) a[A[len[i]]--] = i; //for(int i = 1; i <= tot; i++) siz[i] = 1; if(opt == 1) for(int i = tot; i; i--) right[fa[a[i]]] += right[a[i]]; if(opt == 0) for(int i = tot; i; i--) right[a[i]] = 1; for(int i = tot; i; i--) { siz[a[i]] = right[a[i]]; for(int j = 0; j <= 25; j++) siz[a[i]] += siz[ch[a[i]][j]]; } } int main() { #ifdef WIN32 freopen("a.in", "r", stdin); #endif scanf("%s", s + 1); opt = read(), K = read(); N = strlen(s + 1); for(int i = 1; i <= N; i++) insert(s[i] - 'a'); Topsort(); Query(K); return 0; }

相關推薦

洛谷3975 BZOJ3998 TJOI2015 字尾自動機

題目連結、 題意: 給你一個字串,問你在算重複/不算重複的情況下第k大的字串是什麼,不存在輸出-1。n<=5e5。 題解: 如果不算重複的話和這個題一樣。看連結裡的題解就行,我不再重複了。 那麼我們就講一下算重複的做法。算重複其實就是要通過right來計算相同的情況,計

BZOJ3998: [TJOI2015](字尾自動機)

#include<cstdio> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int MAXN = 1e6 + 10; inl

BZOJ 3998: [TJOI2015] 字尾自動機

3998: [TJOI2015]弦論 Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 4251  Solved: 1562 [Submit][Status][Di

BZOJ 3998 [TJOI2015] (字尾自動機)

題目大意: 給你一個字串,求字典序第$k$小的串是什麼 先建出$sam$和$parent$樹 在$trs$圖中,從根走向節點x的每一條路徑都是x能代表的一個字串 $parent$樹以 某個節點為根的子樹內$endpos$節點的數量,表示這個節點 能代表的所有字串 正序作為字尾在所有字首串中出現的次數

BZOJ 3998: [TJOI2015](字尾自動機

傳送門 解題思路   \(T=0\)時就和SP7258一樣,\(T=1\)時其實也差不多,只不過要把每個點原來是\(1\)的權值改為\(Right\)集合的大小。 程式碼 #include<iostream> #include<cstdio> #include<cstri

bzoj 3998 [TJOI2015]——字尾自動機

題目:https://www.lydsy.com/JudgeOnline/problem.php?id=3998 相同子串算多個的話,先求好 right ,然後求一個 sm 表示走到這個點之後有幾種走法,即把 DAG 上自己能走到的點的 right 都收集起來,可用拓撲序解決。 相同子串算一個的話,給 D

[bzoj3998][TJOI2015]——後綴自動機

tjoi2015 back getchar() ont for () strlen 直接 clu 題目大意: 給定一個字符串,求它的第k小子串。 思路: 後綴自動機的模板題。 考慮將後綴自動機建出來之後,求出每一個狀態在原串中出現了多少次,然後統計以每個節點往後拓展的字符串

bzoj3998 [TJOI2015]

parent freopen eof strlen utc -i name 我們 stdin Description 對於一個給定長度為N的字符串,求它的第K小子串是什麽。 Input 第一行是一個僅由小寫英文字母構成的字符串S 第二行為兩個整數T和K,

[bzoj3998][TJOI2015]

bits 統計 sca zoj 後綴自動機 put con 排序 val 後綴自動機絲薄題。 求給定字符串$s$的第$k$大的子串。分unique之後的和不unique的兩種詢問。 首先構建出SAM。 相同子串算一個的情況: SAM上所有路徑組成字符串$s$的全部子串

Bzoj3998: [TJOI2015]

space urn fill 後綴 math size || bzoj3998 mem 題面 傳送門 Sol \(sam\) 求一個串的不重復的第\(k\)小子串很好辦 如果可以相同 那麽要算上每個點(前綴)的後綴的個數 那麽就是這個\(endpos(right)\)集合的

BZOJ3998 TJOI2015(後綴數組+二分答案)

print eof read 二分 否則 二分答案 scan out close 先看t=1的情況。顯然得求出SA(因為我不會SAM)。我們一位位地確定答案。設填到了第len位,二分這一位填什麽之後,在已經確定的答案所在的範圍(SA上的某段區間)內二分,找到最後一個小於當前

[TJOI2015]字尾自動機

3998: [TJOI2015]弦論 Description 對於一個給定長度為N的字串,求它的第K小子串是什麼。 Input 第一行是一個僅由小寫英文字母構成的字串S 第二行為兩個整數T和K,T為0則表示不同位置的相同子串算作一個。T=1則表示不同位置的相同子串算作多

[TJOI2015]字尾陣列or字尾自動機

解法一:字尾陣列 聽說字尾陣列解第k小本質不同的子串是一個經典問題。 把字尾排好序後第i個串的本質不同的串的貢獻就是\(n-sa[i]+1-LCP(i,i-1)\)然後我們累加這個貢獻,看到哪一個串的時候,這個貢獻的和大於等於k,然後答案就在這個串裡了,然後列舉就行了。 那麼第k小子串該怎麼辦? 我們考慮二

BZOJ3998(後綴自動機

span return last log map div com inline main 【BZOJ3998】弦論(後綴自動機) 題面 BZOJ 題解 這題應該很簡單 構建出\(SAM\)後 求出每個點往後還能構建出幾個串 按照拓撲序\(dp\)一些就好了 然後就是第\(k

BZOJ.3998.[TJOI2015](後綴自動機)

[1] size clu php scan 合並 如果 inline int 題目鏈接 \(Description\) 給定字符串S,求其第K小子串。(若T=0,不同位置的相同子串算1個;否則算作多個) \(Solution\) 建SAM,處理出對於每個節點,它和它的所有後

BZOJ_3998_[TJOI2015]_後綴自動機

整數 字母 In 英文 out pan str spa test BZOJ_3998_[TJOI2015]弦論_後綴自動機 Description 對於一個給定長度為N的字符串,求它的第K小子串是什麽。 Input 第一行是一個僅由小寫英文字母構成的字

[TJOI2015]

tput 第k小 http str scrip back stack air 輸出 [TJOI2015]弦論 Time Limit: 10 Sec Memory Limit: 256 MB[Submit][Status][Discuss] Description

【刷題】BZOJ 3998 [TJOI2015]

con dfs tchar out zoj reg pan long long 其余 Description 對於一個給定長度為N的字符串,求它的第K小子串是什麽。 Input 第一行是一個僅由小寫英文字母構成的字符串S 第二行為兩個整數T和K,T為0則表示不同位置的相同子

TJOI2015

題目描述 題解: 鑑於子串我們很容易想到字尾自動機。 先建字尾自動機,然後處理單點價值以及對於每個點的總價值。 T=0要求去重,此時單點價值為1; T=0要求不去重,此時單點價值為parent樹上endpos的數量。字尾的字首就是子串。 由於建成的字尾自動機有向無環,我們可以O(n)時間處理每個點

luogu P3975 [TJOI2015]

傳送門 對原串構建SAM,然後在上面走出這個串,聯絡Splay求第k大,需要知道每個狀態往後走總共有多少子串,這個可以按照拓撲序逆序dp得到(至於dp初始狀態,本質相同子串算一個就為1,否則為endpos的大小) #include<bits/stdc++.h> #define LL long