HAOI 2016 找相同字元 題解

2021-10-05 15:31:43 字數 1821 閱讀 4407

題目傳送門

題目大意:問兩個字串有多少對相同的子串(位置不同算兩對)。

以乙個字串造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...