zoukankan      html  css  js  c++  java
  • [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;
    }
  • 相关阅读:
    锤子科技官网:问题整理及注意事项
    springboot中文文档
    Spring Framework 开发参考手册中文(在线HTML)
    .is() 全选复选的判断
    c:forEach用法
    SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)
    火狐浏览器下载文件保存文件名的乱码问题
    多线程安全的解决方法
    MySQL的concat以及group_concat的用法
    mysql 将时间转换成时间戳
  • 原文地址:https://www.cnblogs.com/evenbao/p/10046843.html
Copyright © 2011-2022 走看看