洛谷P3975 弦論

2022-04-30 11:18:10 字數 3139 閱讀 3963

題意:求乙個串的字典序第k小的子串/本質不同第k小的子串。

解:一開始我的想法是在字尾樹上找,但是不知道字尾樹上的邊對應的是哪些字元...

然而可以不用fail樹轉移,用轉移邊轉移即可。

先建乙個字尾自動機,記憶化搜尋每個節點向後向後有多少個串。

然後從起點開始向後乙個字元乙個字元的確定。

注意每到乙個新點就要判斷是否結束,並把k減去在此結束的串的個數。

1 #include 2 #include 3

4const

int n = 1000010;5

6int tr[n][26

], len[n], fail[n], siz[n], bin[n], cnt[n], topo[n];

7int

top, last;

89 inline void

init()

1314 inline void insert(char

c) 24

if(!p)

27else

32else42}

43}44return;45

}4647 inline void

sort()

51for(int i = 1; i <= top; i++)

54for(int i = 1; i <= top; i++)

57return;58

}5960 inline void

count()

65return;66

}6768char

s[n];

6970

int dfs(int

x) 74 siz[x] =cnt[x];

75for(int i = 0; i < 26; i++) 79}

80return

siz[x];81}

8283

intmain()

90sort();

91int

flag, k;

92 scanf("

%d%d

", &flag, &k);

93if

(flag)

96else

100}

101102

int sum = 0

;103

for(int i = 2; i <= top; i++)

106107

int p = 1

;108

dfs(p);

109if(k >sum)

113 cnt[1] = 0

;114

while(1

) 119

else

122//

printf("k = %d p = %d \n", k, p);

123for(int i = 0; i < 26; i++)

127if(siz[tr[p][i]] >=k)

132else

135}

136}

137138

return0;

139 }

ac**

又思考了一下,雖然記憶化搜尋會搜到重複的節點,但是這些重複所表示的是到達它的不同方案,也就是它代表的不同子串。所以需要重複統計。

這樣乙個節點的一條轉移邊其實就是它下乙個字元拼上f之後能形成的子串數。

感覺好神奇...

[update] 剛發現k=1的時候錯了……………………稍微改一下就行。

1 #include 2 #include 3

4const

int n = 1000010;5

6int tr[n][26

], len[n], fail[n], siz[n], bin[n], cnt[n], topo[n];

7int

top, last;

89 inline void

init()

1314 inline void insert(char

c) 24

if(!p)

27else

32else42}

43}44return;45

}4647 inline void

sort()

51for(int i = 1; i <= top; i++)

54for(int i = 1; i <= top; i++)

57return;58

}5960 inline void

count()

65return;66

}6768char

s[n];

6970

int dfs(int

x) 74 siz[x] =cnt[x];

75for(int i = 0; i < 26; i++) 79}

80return

siz[x];81}

8283

intmain()

90sort();

91int

flag, k;

92 scanf("

%d%d

", &flag, &k);

93if

(flag)

96else

100}

101102

int sum = 0

;103

for(int i = 2; i <= top; i++)

106107

int p = 1

;108

dfs(p);

109if(k >sum)

113 ++k;

114 cnt[1] = 1

;115

while(1

) 120

else

123//

printf("k = %d p = %d \n", k, p);

124for(int i = 0; i < 26; i++)

128if(siz[tr[p][i]] >=k)

133else

136}

137}

138139

return0;

140 }

更正確的ac**

洛谷P3975 TJOI2015 弦論

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

P3975 (字尾自動機sort)

求出所有字串的第k大子串 有兩種,第一種對於出現在不同位置的相同子串算作乙個子串 第二種,對於不同位置的子串算作是不相同子串 1 leq s leq5000 00 對於第一種計算,endpos算作1,對於第二種,endpos是狀態出現的次數 對於當前狀態字首出現的次數為endpos 子狀態的出現次數...

P3975 TJOI2015 弦論 第K小子串

為了提高智商,zjy開始學習弦論。這一天,她在 string theory 中看到了這樣一道問題 對於乙個給定的長度為n的字串,求出它的第k小子串是什麼。你能幫幫她嗎?第一行是乙個僅由小寫英文本母構成的字串s 第二行為兩個整數t和k,t為0則表示不同位置的相同子串算作乙個,t為1則表示不同位置的相同...