zoukankan      html  css  js  c++  java
  • 洛谷P3181 后缀数组

    https://www.luogu.org/problem/P3181

    题目要求求出两个两个字符串中相同子串的方案数,那么我们将其拼接起来,去求出拼接后的字符串中含有相同子串的数量。

    当然这样做会求出同一个字符串中相同子串的数量,所以我们还需要如法炮制分别求出两个字符串中的答案,然后用总贡献减去他们。

    那么问题就变成了如何求出一个字符串中相同子串的数量。

    实际上这就是求任意两个后缀x,y的lcp(x,y)和,利用后缀数组,可以知道任意两个lcp(x,y)为min{Height[i]} x <= i <= y

    所以说问题在利用后缀数组求出Height数组之后转化为了如何求Height所有子区间内最小值的和。

    事实上这是一个经典的利用DP做的问题,求解一个序列中任意子区间的最小值的和,设置L[i]表示最左端的大于a[i]的下标,R[i]表示最右端的大于等于a[i]的下标,注意需要左闭右开,然后在求出来之后对于每个位置,对答案的贡献就是 a[i] * (i - L[i] + 1) * (R[i] - i + 1)

    注意事项:在拼接字符串的过程中,需要在两字符串中间增加一个'z' + 1的字符,防止出现取到的相同子串跨越两个被拼接的字符串

    #include <map>
    #include <set>
    #include <ctime>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <string>
    #include <bitset>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <sstream>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    using namespace std;
    #define For(i, x, y) for(int i=x;i<=y;i++)  
    #define _For(i, x, y) for(int i=x;i>=y;i--)
    #define Mem(f, x) memset(f,x,sizeof(f))  
    #define Sca(x) scanf("%d", &x)
    #define Sca2(x,y) scanf("%d%d",&x,&y)
    #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
    #define Scl(x) scanf("%lld",&x)  
    #define Pri(x) printf("%d
    ", x)
    #define Prl(x) printf("%lld
    ",x)  
    #define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
    #define LL long long
    #define ULL unsigned long long  
    #define mp make_pair
    #define PII pair<int,int>
    #define PIL pair<int,long long>
    #define PLL pair<long long,long long>
    #define pb push_back
    #define fi first
    #define se second 
    typedef vector<int> VI;
    int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();}
    while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;}
    const double PI = acos(-1.0);
    const double eps = 1e-9;
    const int maxn = 4e5 + 10;
    const int INF = 0x3f3f3f3f;
    const int mod = 1e9 + 7;
    const int SP = 20; 
    int M,K,l1,l2,l;
    char str[maxn]; 
    int sa[maxn],rak[maxn],tex[maxn],tp[maxn],Height[maxn];
    void Qsort(int N){
        for(int i = 0; i <= M ; i ++) tex[i] = 0;
        for(int i = 1; i <= N ; i ++) tex[rak[i]]++;
        for(int i = 1; i <= M ; i ++) tex[i] += tex[i - 1];
        for(int i = N; i >= 1 ; i --) sa[tex[rak[tp[i]]]--] = tp[i];
    }
    void SA(char *str,int N){
        for(int i = 1; i <= N ; i ++) rak[i] = str[i] - '0' + 1,tp[i] = i;
        Qsort(N);    
        for(int w = 1,p = 0; p < N; M = p, w <<= 1){
            p = 0;
            for(int i = 1; i <= w; i ++) tp[++p] = N - w + i;
            for(int i = 1; i <= N ; i ++) if(sa[i] > w) tp[++p] = sa[i] - w;
            Qsort(N);
            swap(rak,tp);
            rak[sa[1]] = p = 1;
            for(int i = 2; i <= N ; i ++){
                rak[sa[i]] = (tp[sa[i]] == tp[sa[i - 1]] && tp[sa[i] + w] == tp[sa[i - 1] + w])?p:++p;
            }
        }
    }
    void GetHeight(char *str,int N){
        int j,k = 0;
        for(int i = 1; i <= N ; i ++){
            if(k) k--;
            int j = sa[rak[i] - 1];
            while(i + k <= N && j + k <= N && str[i + k] == str[j + k]) k++;
            Height[rak[i]] = k;
        }
    }
    LL L[maxn],R[maxn];
    LL work(int* a,int n){
        for(int i = 1; i <= n ; i ++){
            L[i] = i;
            while(L[i] != 1 && a[i] < a[L[i] - 1]) L[i] = L[L[i] - 1];
        }
        for(int i = n; i >= 1; i --){
            R[i] = i;
            while(R[i] != n && a[i] <= a[R[i] + 1]) R[i] = R[R[i] + 1];
        }
        LL ans = 0;
        for(int i = 1; i <= n ; i ++){
            ans += a[i] * ((R[i] - i + 1) * (i - L[i] + 1));
        }
        return ans;
    }
    int main(){
        scanf("%s",str + 1); l1 = strlen(str + 1);
        str[l1 + 1] = 'z' + 1;
        scanf("%s",str + 2 + l1); l2 = strlen(str + 2 + l1);
        l = l1 + l2 + 1;
        M = 122; SA(str,l);
        LL ans = 0; GetHeight(str,l);
        ans += work(Height + 1,l - 1);
        M = 122; SA(str,l1);
        GetHeight(str,l1);
        ans -= work(Height + 1,l1 - 1);
        M = 122; SA(str + l1 + 1,l2);
        GetHeight(str + l1 + 1,l2);
        ans -= work(Height + 1,l2 - 1);
        Prl(ans);
        return 0;
    }
  • 相关阅读:
    linux下LD_PRELOAD的用处
    三个通用的脚本,处理MySQL WorkBench导出表的JSON数据进SQLITE3
    ubuntu 18.04下,KMS_6.9.1服务器启动后,客户端连接一段时间因为libnice而crash的问题修复
    Daliy Algorithm(线段树&组合数学) -- day 53
    Daliy Algorithm(链表&搜索&剪枝) -- day 52
    Daliy Algorithm(二分&前缀和) -- day 51
    每日算法
    动态规划--01背包模型
    每日算法
    每日算法
  • 原文地址:https://www.cnblogs.com/Hugh-Locke/p/11296337.html
Copyright © 2011-2022 走看看