P3975 TJOI2015 弦論 第K小子串

2021-09-25 16:56:58 字數 1691 閱讀 7802

為了提高智商,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。

利用字尾自動機求解

endpos 大小就是  有多少個這樣的子串

按照parent 反拓撲序 求 sum [  i ]   (經過自動機每個節點的子串數目)

關於反拓撲序的解釋

將所有的parent 反過來,我們就得到了parent樹

如果要處理什麼,就需要parent樹的拓撲序

(因為parent相當於包含了所有的他的子樹,都需要更新上去)

其實不需要拓撲排序

我們知道s 的endpos完全被parent 的endpos包含

s.longest一定長於parent.longest

所以,乙個狀態的longest越長,它一定要被更先訪問

所以,按照longest 的長度進行桶排序就可以解決拓撲序了

求出來之後按照字典序遍歷即可

參考

#include#include#include#includeusing namespace std;

typedef long long ll;

const int maxn=5e5+5;

struct sam

void extend(int c)

if(!p)

slink[np]=root;

else

}else

slink[np]=q;

}last=np;

endpos[np]=1;

}void build(string s)

}}sam;

ll sum[maxn<<1];

void f(int x,int k)

else}}

}int main()

}else if(t==1)

}sum[1]=0;

sam.endpos[1]=0;

for(int i=sam.now;i>=sam.root;i--)

}if(sum[sam.root]printf("-1");

else

f(1,k);

return 0;

}

洛谷P3975 TJOI2015 弦論

題目大意 求乙個字串的第 k 大字串,t 表示長得一樣位置不同的字串是否算多個 題解 sam 先求出每個位置可以到達多少個字串 right 陣列 然後在轉移圖上 dp 若 t 1 初始值賦成 right 陣列大小,否則賦成 1 卡點 無 c code include include include ...

洛谷P3975 弦論

題意 求乙個串的字典序第k小的子串 本質不同第k小的子串。解 一開始我的想法是在字尾樹上找,但是不知道字尾樹上的邊對應的是哪些字元.然而可以不用fail樹轉移,用轉移邊轉移即可。先建乙個字尾自動機,記憶化搜尋每個節點向後向後有多少個串。然後從起點開始向後乙個字元乙個字元的確定。注意每到乙個新點就要判...

TJOI2015 弦論(第k小子串)

題意 對於乙個給定的長度為n的字串,求出它的第k小子串。有引數t,t為0則表示不同位置的相同子串算作乙個,t為1則表示不同位置的相同子串算作多個。題解 首先,因為t的原因,字尾陣列較難實現,這裡不討論。使用字尾自動機 因為,這裡需要按字典序考慮子串,所以要使用trs指標。首先,計算出每個子串的貢獻 ...