• BZOJ 3238 [Ahoi2013] 差异 | 后缀数组 单调栈


    BZOJ 3238 [Ahoi2013] 差异 | 后缀数组 单调栈


    题面

    ![](http://www.lydsy.com/JudgeOnline/upload/201306/1(4).jpg)

    数据范围:(2le Nle 500000)

    题解

    这是一道后缀数组模板题!

    在学校停电没Wifi、自己流量又不舍得用的情况的逼迫下,我!终于!会自己背着写后缀数组了!

    观察这个式子,发现(len(T_i) + len(T_j))这部分和后面的完全没有关系嘛,所以拎出来单独处理,那么所求就变成了

    [(sum_{1le i < j le n} len(T_i) + len(T_j)) - 2 * sum_{1le i < j le n} lcp(T_i, T_j) ]

    左边那半部分就是((n - 1) * n * (n + 1) / 2)啦。至于右边那部分,就是任意一对后缀的lcp,显然使用后缀数组。

    一开始我居然想写个维护后缀最大值的树状数组什么的来维护这个东西……

    根据后缀数组的性质,把height数组看成一个序列,要求的就是每个子区间的最小值之和。这个东西当然是用单调栈来做啦!单调栈求出每个元素左边第一个比它大的位置和右边第一个比它大的位置,然后就可以求出有多少区间以它为最小值,区间数*这个最小值,加起来,就是答案啦。

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    #define enter putchar('
    ')
    #define space putchar(' ')
    template <class T>
    void read(T &x){
        char c;
        bool op = 0;
        while(c = getchar(), c > '9' || c < '0')
    	if(c == '-') op = 1;
        x = c - '0';
        while(c = getchar(), c >= '0' && c <= '9')
    	x = x * 10 + c - '0';
        if(op) x = -x;
    }
    template <class T>
    void write(T x){
        if(x < 0) putchar('-'), x = -x;
        if(x >= 10) write(x / 10);
        putchar('0' + x % 10);
    }
    const int N = 500005;
    int n, buf1[N], buf2[N], buc[N], sa[N], rnk[N], height[N], tol[N], tor[N], stk[N], top;
    ll ans;
    char s[N];
    void suffix_sort(){
        int *x = buf1, *y = buf2, m = 128;
        for(int i = 0; i <= m; i++) buc[i] = 0;
        for(int i = 1; i <= n; i++) buc[x[i] = s[i]]++;
        for(int i = 1; i <= m; i++) buc[i] += buc[i - 1];
        for(int i = n; i; i--) sa[buc[x[i]]--] = i;
        for(int k = 1, p = 0; k <= n && p < n; k *= 2, m = p, 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) y[++p] = sa[i] - k;
            for(int i = 0; i <= m; i++) buc[i] = 0;
            for(int i = 1; i <= n; i++) buc[x[y[i]]]++;
            for(int i = 1; i <= m; i++) buc[i] += buc[i - 1];
            for(int i = n; i; i--) sa[buc[x[y[i]]]--] = y[i];
            p = 1, swap(x, y), x[sa[1]] = 1;
            for(int i = 2; i <= n; i++)
                x[sa[i]] = (y[sa[i] + k] == y[sa[i - 1] + k] && y[sa[i]] == y[sa[i - 1]]) ? p : ++p;
        }
        for(int i = 1; i <= n; i++) rnk[sa[i]] = i;
        for(int i = 1, k = 0; i <= n; i++){
            if(rnk[i] == 1) continue;
            int j = sa[rnk[i] - 1];
            if(k) k--;
            while(i + k <= n && j + k <= n && s[i + k] == s[j + k]) k++;
            height[rnk[i]] = k;
        }
    }
    int main(){
        scanf("%s", s + 1), n = strlen(s + 1);
        suffix_sort();
        stk[top = 1] = 1;
        for(int i = 2; i <= n; i++){
            while(top > 1 && height[i] < height[stk[top]]) tor[stk[top--]] = i;
            tol[i] = stk[top];
            stk[++top] = i;
        }
        while(top > 1) tor[stk[top--]] = n + 1;
        for(int i = 2; i <= n; i++)
            ans += (ll) height[i] * (i - tol[i]) * (tor[i] - i);
        write((ll)(n + 1) * n / 2 * (n - 1) - 2 * ans), enter;
        return 0;
    }
    
  • 相关阅读:
    【转】python:让源码更安全之将py编译成so
    [转]Ubuntu python-config
    【转】动态复权(真实价格)模式原理详解!
    [转]Aroon Indicator
    LeetCode 852. Peak Index in a Mountain Array
    LeetCode 1257. Smallest Common Region
    LeetCode 1034. Coloring A Border
    LeetCode 348. Design Tic-Tac-Toe
    LeetCode 452. Minimum Number of Arrows to Burst Balloons
    LeetCode 733. Flood Fill
  • 原文地址:https://www.cnblogs.com/RabbitHu/p/BZOJ3238.html
Copyright © 2020-2023  润新知