zoukankan      html  css  js  c++  java
  • AcWing 1004. 品酒大会 (后缀数组,并查集)

    题目链接

    解题思路

      从后缀数组的角度考虑,利用(lcp)的性质,(lcp(i, j) = min(lcp(k_1, k_2), i leq k_1,k_2 leq j)。那么对于所有“r相似”的后缀来说他们之间的(lcp)肯定是大于等于(r)的。我们可以考虑根据lcp的大小按顺序将所有后缀加入集合,从而维护一系列lcp大于等于r的集合进而求得所有符合条件的后缀对数,这就是经典的并查集维护集合问题。

    代码

    const int maxn = 3e5+10;
    char s[maxn];
    int n, m;
    int sa[maxn], x[maxn], y[maxn], c[maxn], rk[maxn], h[maxn];
    void get_sa() {
        for (int i = 1; i<=n; ++i) ++c[x[i]=s[i]];
        for (int i = 2; i<=m; ++i) c[i] += c[i-1];
        for (int i = n; i; --i) sa[c[x[i]]--] = i;
        for (int k = 1; k<=n; k<<=1) {
            int num = 0;
            for (int i = n-k+1; i<=n; ++i) y[++num] = i;
            for (int i = 1; i<=n; ++i)
                if (sa[i]>k) y[++num] = sa[i]-k;
            for (int i = 1; i<=m; ++i) c[i] = 0;
            for (int i = 1; i<=n; ++i) ++c[x[i]];
            for (int i = 1; i<=m; ++i) c[i] += c[i-1];
            for (int i = n; i; --i) sa[c[x[y[i]]]--] = y[i], y[i] = 0;
            swap(x, y);
            x[sa[1]] = 1, num = 1;
            for (int i = 2; i<=n; ++i) 
                x[sa[i]] = (y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]) ? num : ++num;
            if (num==n) break;
            m = num;
        }
    }
    vector<P> g[maxn];
    void get_h() {
        for (int i = 1; i<=n; ++i) rk[sa[i]] = i;
        for (int i = 1, k = 0; i<=n; ++i) {
            if (rk[i]==1) continue;
            if (k) --k;
            int j = sa[rk[i]-1];
            while(i+k<=n && j+k<=n && s[i+k]==s[j+k]) ++k;
            h[rk[i]] = k;
            g[k].push_back({sa[rk[i]], sa[rk[i]-1]});
        }
    }
    int p[maxn];
    ll sz[maxn], mx1[maxn], mx2[maxn], mi1[maxn], mi2[maxn];
    int fd(int x) {
        return p[x]==x ? p[x]:p[x]=fd(p[x]);
    }
    ll sum = 0, ans = -2e18;
    void calc(int x) {
        for (auto t :g[x]) {
            int fa = fd(t.x);
            int fb = fd(t.y);
            if (fa!=fb) {
                sum += 1LL*sz[fa]*sz[fb];
                p[fa] = fb;
                sz[fb] += sz[fa];
                if (mx1[fa]>=mx1[fb]) mx2[fb] = max(mx1[fb], mx2[fa]), mx1[fb] = mx1[fa];
                else if (mx1[fa]>mx2[fb]) mx2[fb] = mx1[fa];
                if (mi1[fa]<=mi1[fb]) mi2[fb] = min(mi1[fb], mi2[fa]), mi1[fb] = mi1[fa];
                else if (mi1[fa]<mi2[fb]) mi2[fb] = mi1[fa];
                ans = max({ans, 1LL*mx1[fb]*mx2[fb], 1LL*mi1[fb]*mi2[fb]});
            }
        }
    }
    int main() {
        IOS;
        cin >> n, m = 122;
        cin >> s+1;
        get_sa(); get_h();
        for (int i = 1; i<=n; ++i) {
            cin >> mx1[i]; 
            mi1[i] = mx1[i];
            mx2[i] = -2e18, mi2[i] = 2e18;
            p[i] = i, sz[i] = 1;
        }
        vector<P> t;
        for (int i = n-1; i>=0; --i) {
            calc(i);
            t.push_back({sum, ans<-1.5e18 ? 0:ans});
        }
        for (int i = t.size()-1; i>=0; --i) cout << t[i].x << ' ' << t[i].y << endl;
        return 0; 
    }
    
  • 相关阅读:
    Navicat for MySQL下载、安装与破解
    javaweb之Cookie学习
    static特别用法【静态导包】——Java包的静态导入
    面试感悟----一名3年工作经验的程序员应该具备的技能
    致孩子
    java中的代码块是什么意思,怎么用
    ModelAttribute用法之一
    SpringMVC获取页面数据乱码的解决get/post
    总结过去10年的程序员生涯 (经验)---大神的建议
    hdu 5237 二进制
  • 原文地址:https://www.cnblogs.com/shuitiangong/p/15233799.html
Copyright © 2011-2022 走看看