BZOJ4566 [Haoi2016]找相同字元 【尾碼數組】

來源:互聯網
上載者:User

標籤:body   logs   尾碼數組   ring   efi   while   cal   getchar   wap   

題目

給定兩個字串,求出在兩個字串中各取出一個子串使得這兩個子串相同的方案數。兩個方案不同若且唯若這兩
個子串中有一個位置不同。

輸入格式

兩行,兩個字串s1,s2,長度分別為n1,n2。1 <=n1, n2<= 200000,字串中只有小寫字母

輸出格式

輸出一個整數表示答案

輸入範例

aabb

bbaa

輸出範例

10

題解

先考慮暴力怎麼做
我們枚舉兩個串的各自一個尾碼suffix(i)和suffix(j)
則他們對答案的貢獻是LCP(suffix(i),suffix(j))
如此得到一個\(O(n^3)\)的演算法

當然如果你知道尾碼數組,可以\(O(1)\)求LCP,可以最佳化到\(O(n^2)\)

當然如果你知道尾碼數組的套路,用一個單調棧掃一遍height[]可以做到\(O(nlogn)\)【主要複雜度在求尾碼數組】
具體這樣:
我們知道,兩個尾碼之間的LCP是他們之間height的最小值
如果給出一個位置的尾碼,想求這個位置之前所有的尾碼與這個位置的LCP之和之類的東西,由於求最小值是一路過去的,所以前面的尾碼的LCP不會比後面的大,所以整體是單調不下降的,可以用單調棧處理

最後我們只需要分A、B串各用單調棧掃兩次統計出答案就可以了

#include<iostream>#include<cmath>#include<cstdio>#include<cstring>#include<algorithm>#define LL long long int#define REP(i,n) for (int i = 1; i <= (n); i++)#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<‘ ‘; puts("");using namespace std;const int maxn = 400005,maxm = 100005,INF = 1000000000;inline int read(){    int out = 0,flag = 1; char c = getchar();    while (c < 48 || c > 57) {if (c == ‘-‘) flag = -1; c = getchar();}    while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - ‘0‘; c = getchar();}    return out * flag;}int sa[maxn],rank[maxn],height[maxn],t1[maxn],t2[maxn],bac[maxn],n,m;char s[maxn];int len;LL ans;void getSA(){    int *x = t1,*y = t2; m = 256;    for (int i = 0; i <= m; i++) bac[i] = 0;    for (int i = 1; i <= n; i++) bac[x[i] = s[i]]++;    for (int i = 1; i <= m; i++) bac[i] += bac[i - 1];    for (int i = n; i; i--) sa[bac[x[i]]--] = i;    for (int k = 1; k <= n; k <<= 1){        int p = 0;        for (int i = n - k + 1; i <= n; i++) y[++p] = i;        for (int i = 1; i <= n; i++) if (sa[i] - k > 0) y[++p] = sa[i] - k;        for (int i = 0; i <= m; i++) bac[i] = 0;        for (int i = 1; i <= n; i++) bac[x[y[i]]]++;        for (int i = 1; i <= m; i++) bac[i] += bac[i - 1];        for (int i = n; i; i--) sa[bac[x[y[i]]]--] = y[i];        swap(x,y);        p = x[sa[1]] = 1;        for (int i = 2; i <= n; i++)            x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k] ? p : ++p);        if (p >= n) break;        m = p;    }    for (int i = 1; i <= n; i++) rank[sa[i]] = i;    for (int i = 1,k = 0; i <= n; i++){        if (k) k--;        int j = sa[rank[i] - 1];        while (s[i + k] == s[j + k]) k++;        height[rank[i]] = k;    }}int st[maxn],cnt[maxn],top;LL cal[maxn];void solve(){    for (int i = 1; i <= n; i++){        if (!height[i]) {top = 0; continue;}        int tot = sa[i - 1] <= len ? 1 : 0;        while (top && st[top] > height[i]) tot += cnt[top--];        if (tot) st[++top] = height[i],cnt[top] = tot;        cal[top] = cal[top - 1] + (LL)st[top] * (LL)cnt[top];        if (sa[i] > len) ans += cal[top];    }    top = 0;    for (int i = 1; i <= n; i++){        if (!height[i]) {top = 0; continue;}        int tot = sa[i - 1] > len ? 1 : 0;        while (top && st[top] > height[i]) tot += cnt[top--];        if (tot) st[++top] = height[i],cnt[top] = tot;        cal[top] = cal[top - 1] + (LL)st[top] * (LL)cnt[top];        if (sa[i] <= len) ans += cal[top];    }}int main(){    scanf("%s",s + 1); len = strlen(s + 1);    s[len + 1] = ‘#‘;    scanf("%s",s + len + 2);    n = strlen(s + 1);    getSA();    solve();    cout << ans << endl;    return 0;}

BZOJ4566 [Haoi2016]找相同字元 【尾碼數組】

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.