zoukankan      html  css  js  c++  java
  • [AHOI2013]差异

    Description

    BZOJ3238
    Luogu4248
    (sum_{1le i < jle n}(len(suf_i)+len(suf_j)-2lcp(suf_i,suf_j)))

    Solution

    看到(lcp)就直接上后缀数组。对于求和的前两项推公式直接(O(1))出,最后一项依次计算每个(h)的贡献。具体来说就是降序排序h后,计算有多少对的询问的答案是(h_i),这个可以用并查集搞。

    Code

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    const int N = 5e5 + 10;
    
    int sa[N], rnk[N], tmp[N], tax[N], h[N];
    int n, m, a[N], p[N];
    char s[N];
    int fa[N], sz[N];
    
    void rsort() {
        for (int i = 1; i <= m; ++i) tax[i] = 0;
        for (int i = 1; i <= n; ++i) ++tax[rnk[i]];
        for (int i = 1; i <= m; ++i) tax[i] += tax[i-1];
        for (int i = n; i >= 1; --i) sa[tax[rnk[tmp[i]]]--] = tmp[i];
    }
    
    void ssort() {
        for (int i = 1; i <= n; ++i) rnk[i] = a[i], tmp[i] = i;
        m = 30;
        rsort();
        for (int w = 1, p = 0; p < n; w <<= 1) {
            p = 0;
            for (int i = 1; i <= w; ++i) tmp[++p] = n-w+i;
            for (int i = 1; i <= n; ++i) if (sa[i] > w) tmp[++p] = sa[i]-w;
            rsort();
            std::swap(rnk, tmp);
            rnk[sa[1]] = p = 1;
            for (int i = 2; i <= n; ++i) {
                rnk[sa[i]] = (tmp[sa[i]] == tmp[sa[i-1]] && tmp[sa[i]+w] == tmp[sa[i-1]+w]) ? p : ++p;
            }
            m = p;
        }
        for (int i = 1, k = 0; i <= n; ++i)  {
            if (rnk[i] != 1) while (a[i+k] == a[sa[rnk[i]-1]+k]) ++k;
            else k = 0;
            h[rnk[i]] = k;
            if (k) --k;
        }
    }
    
    int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); }
    
    long long merge(int x, int y) {
        int fx = find(x), fy = find(y);
        if (fx == fy) return 0;
        long long ans = (long long)(sz[fx]) * (sz[fy]);
        fa[fy] = fx;
        sz[fx] += sz[fy];
        return ans;
    }
    
    bool cmp(int a, int b) {
        return h[a] > h[b];
    }
    
    int main() {
        scanf("%s", s);
        n = strlen(s);
        for (int i = 0; i < n; ++i) a[i+1] = s[i]-'a'+1;
        ssort();
        for (int i = 1; i <= n; ++i) {
            fa[i] = i; 
            sz[i] = 1;
            p[i] = i;
        } 
        std::sort(p+1, p+n+1, cmp);
        long long ans = (long long)(n+1)*n*(n-1)/2;
        
        for (int i = 1; i <= n; ++i) {
            ans = ans - merge(p[i], p[i]-1)*h[p[i]]*2;
        }
        printf("%lld
    ", ans);
        return 0;
    }
    

    Note

    一定要注意将字符转化为数字的时候要和这一位没有字符((0))区分开。

  • 相关阅读:
    2018.6.8 现代企业管理复习总结
    写时复制
    字符串类示例
    信号量示例
    对象赋值的语义
    对象复制的语义
    无用单元和悬挂引用
    初始化
    静态数据成员,静态成员函数
    同时找出最大数和最小数
  • 原文地址:https://www.cnblogs.com/wyxwyx/p/bzoj3238.html
Copyright © 2011-2022 走看看