loj2064 找相同字元

2022-05-09 12:36:11 字數 1477 閱讀 4916

portal --> loj2064

這裡是用字尾陣列做的版本!(晚點再用sam寫一遍qwq)

​  首先乙個字串的子串其實就是這個字串某個字尾的字首,所以我們有乙個十分簡單粗暴的想法直接把兩個串接起來(常用套路:中間加乙個最大的字元作為分隔符)然後求sa,求完之後我們就可以十分愉快地獲得乙個\(o(n^2)\)的演算法了(每次列舉兩個字尾,然後經過預處理之後我們可以用st表\(o(1)\)求得lcp,答案顯然就是這堆lcp之和)

然而\(o(n^2)\)十分不優秀,這裡我們可以反過來想每乙個\(height[i]\)可以在哪乙個範圍內作為最小值,具體的話我們可以用遞迴來實現

為了方便表示,我們記\(cnt1[i]\)表示排名前\(i\)的字尾中,屬於第乙個串的字尾數量,\(cnt2[i]\)表示排名前\(i\)的字尾中,屬於第二個串的字尾數量

記\(solve(l,r)\)表示處理\(rk\)值\(\in [l,r]\)的這堆字尾對答案的貢獻,我們可以用st表求的這個區間內的\(height\)最小值為\(x\),然後我們記這個最小值的位置為\(mid\),那麼這個區間內長度為\(x\)的取法對答案的貢獻就是

\[\begin

x&*((cnt1[mid-1]-cnt1[l-1])*(cnt2[r]-cnt2[mid-1])+(cnt2[mid-1]-cnt2[l-1])*(cnt1[r]-cnt1[mid-1]))

\end

\]然後接著我們直接遞迴處理\([l,mid-1]\)區間和\([mid,r]\)區間就好了(其實好像區間這個加減的東西可以自己調整一下。。不過相對應的上面的式子中\(cnt1\)和\(cnt2\)的範圍也需要稍微調整一下,都是具體實現個人習慣的問題)

注意答案可能比較大所以需要用long long

**大概長這個樣子

#include#include#include#include#define ll long long

#define pr pair#define mp make_pair

using namespace std;

const int n=200010,sa=n*2,top=20;

char s1[n],s2[n],s[n*2];

int n1,n2,n;

ll ans;

namespace sa

void sort(int n)

void get_sa(int n)

} void rmq(int n)

} void get_ans(int l,int r)

}/*}}}*/

int main(){

#ifndef online_judge

freopen("a.in","r",stdin);

#endif

scanf("%s\n%s",&s1,&s2);

n1=strlen(s1);

n2=strlen(s2);

n=0;

for (int i=0;i

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 陣列所有子區間...

bzoj4566 找相同字元

題意 給定兩個字串,從中各取乙個子串使之相同,有多少種取法。允許本質相同。解 建立廣義字尾自動機,對於每個串,分別統計cnt,之後每個點的cnt乘起來。記得開long long 1 include 2 include 3 include 4 5 typedef long long ll 6 cons...