我們定義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 有一定的關係 這一點主要體現在思想上,兩者都在求解的過程中通過之前已經求解的答案來...