題目傳送門
題目大意:問兩個字串有多少對相同的子串(位置不同算兩對)。
以乙個字串造sam,然後把另乙個字串丟到上面去匹配。
具體是列舉乙個 i
ii,然後看字串 b
bb 的前 i
ii 個字元組成的子串,找到這個子串的最長的 是 a
aa 字串的子串的 字尾。
假設這段字尾是 x
xx ~ i
ii,那麼可以得出,y
yy ~ i(y
∈[x,
i]
)i~(y\in[x,i])
i(y∈[x
,i])
這些字尾都是 a
aa 的乙個子串,而每個字尾的貢獻就是他在 a
aa 中的出現次數,這個可以利用 a
aa 的sam來統計。
說白了,就是要找到這個子串在sam上的對應狀態,然後這個狀態的 end
po
sendpos
endpos
集大小就是了(**中 end
po
sendpos
endpos
集大小記錄在 siz
esize
size
陣列裡)。
但是顯然不可能列舉每乙個字尾去匹配,我們維護乙個 now
nowno
w 和 len
lenle
n,no
wnow
now 表示現在匹配到sam的哪個狀態,len
lenle
n 記錄前 i−1
i-1i−
1 位最多成功匹配多少位,然後如果 now
nowno
w 沒有通過字元 b
ib_i
bi 能到達的後繼狀態,就往後繼鏈結走,直到有能通過 b
ib_i
bi 到達的後置狀態為止,然後更新一下 len
lenle
n,這個狀態的貢獻就是 (le
n−le
n(li
nk(n
ow))
)×si
ze[n
ow
](len-len(link(now)))\times size[now]
(len−l
en(l
ink(
now)
))×s
ize[
now]
,然後還要加上後繼鏈結能到達的那些狀態的貢獻,可以預處理然後 o(1
)o(1)
o(1)
讀取。具體實現就看**吧:
#include
#include
#include
using
namespace std;
#define maxn 400010
#define ll long long
int n;
char s[maxn]
;struct statest[maxn]
;int id=
0,last=
0,now,p,q;
int size[maxn]
;ll sum[maxn]
;void
extend
(int x)
} last=now;
}int c[maxn]
,a[maxn]
;void
work()
ll ans=0;
void
solve()
}int
main()
HAOI2016 找相同字元
給定兩個字串,求出在兩個字串中各取出乙個子串使得這兩個子串相同的方案數。兩個方案不同當且僅當這兩個子串中有乙個位置不同。兩行,兩個字串s1,s2,長度分別為n1,n2。1 n1,n2 200000,字串中只有小寫字母 題解 s1 s2拼起來。求height 要求 i j lcp rk i rk j ...
HAOI2016 找相同字元
其實這道題跟 ahoi2013 差異很像 其實這個問題的本質就是讓你算所有字尾的 lcp 長度之和,但是得來自兩個不同的字串 先把兩個字串拼起來做一遍 sa 由於我們多算了來自於同乙個串內的情況 於是在分別對這兩個串建 sa 減掉這兩次算出來的答案 現在的問題轉化為求出 height 陣列所有子區間...
HAOI 2016 找相同字元
題目鏈結 演算法 首先 子串是字尾的字首 考慮拼接兩個字串 中間用不可見字元隔開 求出該字串的字尾陣列 那麼字首相同的字尾一定排名一定接近 而我們又知道lcp i j min 維護乙個單調遞增的字尾陣列即可 時間複雜度 o nlogn n a b includeusing namespace std...