其實這道題跟[ahoi2013]差異很像
其實這個問題的本質就是讓你算所有字尾的\(lcp\)長度之和,但是得來自兩個不同的字串
先把兩個字串拼起來做一遍\(sa\),由於我們多算了來自於同乙個串內的情況
於是在分別對這兩個串建\(sa\),減掉這兩次算出來的答案
現在的問題轉化為求出\(height\)陣列所有子區間的最小值的和
我們可以考慮乙個動態往序列末尾加數的過程
也就是我們往末尾加乙個數都會和之前所有的數形成乙個新的區間
考慮快速算出這些區間的最小值的和
我們可以對每乙個數儲存乙個\(a_i\),表示\(i\)到當前序列末尾的最小值是多少
我們每次加入乙個數可以對更新一下所有的\(a_i\),把所有比當前加入的數大的\(a_i\)變成當前數就好了
這不就\(t\)了嗎
我們發現我們只需要求出所有\(a_i\)的和,並不需要關心這個\(i\)來自**,於是我們可以把相等的\(a_i\)放在一起計算,也就是每次新加入乙個數就暴力掃一遍把那些比當前加入數大的合併到乙個\(a_i\)裡
看起來複雜度並不科學,但是最壞情況下就相當於是乙個線段樹的複雜度了,\(o(n)\)的,跑的還挺快的
#include#include#include#include#define re register
#define ll long long
#define maxn 400005
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
int het[maxn],sa[maxn],rk[maxn],tp[maxn],tax[maxn];
char s[maxn],t[maxn];
int l1,l2,n,m;
ll a[maxn],cnt[maxn],top;
ll tot;
inline void qsort()
inline ll sa()
int k=0;
for(re int i=1;i<=n;i++)
for(re int i=2;i<=n;i++)
return ans;
}int main()
HAOI2016 找相同字元
給定兩個字串,求出在兩個字串中各取出乙個子串使得這兩個子串相同的方案數。兩個方案不同當且僅當這兩個子串中有乙個位置不同。兩行,兩個字串s1,s2,長度分別為n1,n2。1 n1,n2 200000,字串中只有小寫字母 題解 s1 s2拼起來。求height 要求 i j lcp rk i rk j ...
HAOI 2016 找相同字元
題目鏈結 演算法 首先 子串是字尾的字首 考慮拼接兩個字串 中間用不可見字元隔開 求出該字串的字尾陣列 那麼字首相同的字尾一定排名一定接近 而我們又知道lcp i j min 維護乙個單調遞增的字尾陣列即可 時間複雜度 o nlogn n a b includeusing namespace std...
HAOI2016 找相同字元 SAM
給乙個串建立sam,另乙個在sam上跑匹配,同時計算當前匹配串的所有字尾所產生的的貢獻。由於sam上乙個節點可能不包含所有字尾,要把fat he rfather father 的貢獻下放到son sonso n。詳情見 include include include include include ...