• [AHOI 2013] 差异


    [题目链接]

            https://www.lydsy.com/JudgeOnline/problem.php?id=3238

    [算法]

             首先 , LCP(Ti , Tj) = min{ height[rank[Ti] + 1] , height[rank[Ti] + 2] , ... , height[rank[Tj]] }

             显然 , 我们只要计算后缀两两之间的LCP之和即可

             对于一个右端点R , 随着L的减小 , min{height[L] , height[L + 1] .. , height[R]}的值单调递减 , 维护一个单调递增的单调栈即可

             时间复杂度 : O(NlogN)

    [代码]

             

    #include<bits/stdc++.h>
    using namespace std;
    #define MAXN 500010
    typedef long long ll;
    typedef long double ld;
    const int inf = 1e9;
    
    int n;
    int height[MAXN] , cnt[MAXN] , rk[MAXN] , x[MAXN] , y[MAXN] , sa[MAXN];
    char s[MAXN];
    
    inline ll F(int x)
    {
        return 1ll * x * (x + 1) / 2;
    }
    inline void build_sa()
    {
        memset(cnt , 0 , sizeof(cnt));
        for (int i = 1; i <= n; i++) ++cnt[(int)s[i]];
        for (int i = 1; i <= 256; i++) cnt[i] += cnt[i - 1];
        for (int i = n; i >= 1; i--) sa[cnt[(int)s[i]]--] = i;
        rk[sa[1]] = 1;
        for (int i = 2; i <= n; i++) rk[sa[i]] = rk[sa[i - 1]] + (s[sa[i]] != s[sa[i - 1]]);
        for (int k = 1; rk[sa[n]] != n; k <<= 1)
        {
            for (int i = 1; i <= n; i++)
                x[i] = rk[i] , y[i] = (i + k <= n) ? rk[i + k] : 0;
            memset(cnt , 0 , sizeof(cnt));
            for (int i = 1; i <= n; i++) ++cnt[y[i]];
            for (int i = 1; i <= n; i++) cnt[i] += cnt[i - 1];
            for (int i = n; i >= 1; i--) rk[cnt[y[i]]--] = i;
            memset(cnt , 0 , sizeof(cnt));
            for (int i = 1; i <= n; i++) ++cnt[x[i]];
            for (int i = 1; i <= n; i++) cnt[i] += cnt[i - 1];
            for (int i = n; i >= 1; i--) sa[cnt[x[rk[i]]]--] = rk[i];
            rk[sa[1]] = 1;
            for (int i = 1; i <= n; i++) rk[sa[i]] = rk[sa[i - 1]] + (x[sa[i]] != x[sa[i - 1]] || y[sa[i]] != y[sa[i - 1]]); 
        }
    }
    inline void get_height()
    {
        int k = 0;
        for (int i = 1; i <= n; i++)
        {
            if (k) --k;
            int j = sa[rk[i] - 1];
            while (s[i + k] == s[j + k]) ++k;
            height[rk[i]] = k;
        }    
    }
    inline ll calc_ans()
    {
        int top = 0;
        ll ret = 0;
        static pair<ll , ll> s[MAXN];
        for (int i = 1; i <= n; i++) ret += 1ll * (i - 1) * (n - i + 1) + F(n) - F(n - i + 1);
        s[top = 1] = make_pair(0 , 0);
        ll now = 0;
        for (int i = 1; i <= n; i++)
        {
            int cnt = 1; 
            while (top > 0 && height[i] <= height[s[top].first]) 
            {
                cnt += s[top].second;
                now -= 1ll * height[s[top].first] * s[top].second;
                --top;
            }
            s[++top] = make_pair(i , cnt);
            now += 1ll * height[i] * cnt;
            ret -= 2ll * now;
        }
        return ret;
    }
    
    int main()
    {
        
        scanf("%s" , s + 1);
        n = strlen(s + 1);
        build_sa();
        get_height();
        printf("%lld
    " , calc_ans());
        
        return 0;
    }
  • 相关阅读:
    6 【程序6 最大公约数和最小公倍数】
    5 【程序5 判断分数等级】
    4 【程序4 分解质因数】
    3 【程序3 水仙花数】
    2【程序2 输出素数】
    1 【程序1 不死神兔】
    终极解决傻X阿里钱盾新手开店及老卖家复核身份证照片模糊无法对焦问题
    struct和typedef struct彻底明白了
    CentOS 6.5 编译安装 LNMP环境
    Another MySQL daemon already running with the same unix socket
  • 原文地址:https://www.cnblogs.com/evenbao/p/10046843.html
Copyright © 2020-2023  润新知