擴充套件KMP學習 51nod1304 字串的相似度

2021-07-22 22:06:59 字數 1436 閱讀 4897

我們定義2個字串的相似度等於兩個串的相同字首的長度。例如 「abc」 同 「abd」 的相似度為2,」aaa」 同 「aaab」 的相似度為3。

給出乙個字串s,計算s同他所有字尾的相似度之和。例如:s = 「ababaa」,所有字尾為:

ababaa 6

babaa 0

abaa 3

baa 0

aa 1

a 1

s同所有字尾的相似度的和 = 6 + 0 + 3 + 0 + 1 + 1 = 11

作為乙個拿sam模板隨便刷水的人,這道題很明顯反著插,求出每個狀態right集合大小,從整個串的last一直沿著parent邊往上跑,統計就行了。

結果爆了空間

給定目標串s[1..m]和模板串t[1..n],求出目標串每個字尾與模板串的匹配長度。

設這個長度ext[i]。

假設現在1~i-1的ext都求出來了,現在要求i的,怎麼做呢?

引入乙個新陣列next[i],表示t[i..n]與t的最大匹配長度。

設p=max(ext[a]+a-1),即之前最長匹配到s的**了。p取最大時,設位置為a。

整理一下:目前t[1..p-a+1]=s[a..p](①),那麼t[i-a+1..p-a+1]=s[i..p](②).

我們要求s[i..m]和t[1..n]最長匹配,實質上,s[i..p]這一段我們是不用和t[1..p-i+1]匹配的了。由②得,問題可以轉化為t[1..p-i+1]與t[i-a+1..p-a+1]的匹配,那麼他們匹配長度ext就是min(next[i-a+1],p-i+1),為什麼要取min?因為我們最多隻到p,後面的在s中,我們還沒匹配到過。

如果min取左邊,就不用繼續做了,因為後面一位肯定不相等,不然就不符合next陣列性質。

取右邊,就再往後匹配,並更新a,p。這樣就能o(n)匹配,因為p是不斷往後的。

匹配模組完成了,但是前提是要求next。

next求法跟上面基本一致,只需要把t當做目標串就好了,跟樸素kmp求next方法類似。注意next[1]=n,而且不能被p,a取。

連ext都不用都不用,直接算出next加起來輸出就行···

#include

#include

#include

using namespace std;

#define fo(i,j,k) for(i=j;i<=k;i++)

typedef long long ll;

const int n=1000005;

int i,j,k,n,ts,last,q1,q2,x,next[n],a,p;

char s[n];

ll ans;

int main()

}fo(i,1,n) ans+=next[i];

printf("%lld",ans);

}

擴充套件kmp初學習

參考部落格 問題定義 給出兩個字串s和t 長度分別是n和m 下標從0開始,定義extend i 表示s i s n 1 與t的最長公共字首的長度,求出所有的extend i 如下表i0 1234 567s aaaa abbb taaa aacextend i 54 3210 00如果某個extend...

擴充套件KMP模板(學習)

乙個算是冷門的演算法 在競賽上 不過其演算法思想值得深究。kmp的演算法思想,具體可以參考這篇 trie樹 字典樹 擴充套件kmp的模板問題 給你兩個字串s,t,長度分別為n,m。請輸出s的每乙個字尾與t的最長公共字首。雜湊是不可能的,這輩子都不可能的。mathcalac自動機?好像更不可做了。我們...

擴充套件KMP學習筆記

對於字串 s 定義 z i 為從位置 i 開始的 s 字尾與 s 的最長公共字首的長度。擴充套件 kmp 就是用於在 mathcal o n 複雜度下求解 z 函式的演算法。既然是擴充套件 kmp 那麼當然與 kmp 有一定的關係 這一點主要體現在思想上,兩者都在求解的過程中通過之前已經求解的答案來...