zoukankan      html  css  js  c++  java
  • [NOI2015] 品酒大会

    [NOI2015] 品酒大会

    Description

    对于每一个 (i in [0,n)) 求有多少对后缀满足 LCP 长度 (le i) ,并求满足条件的两个后缀权值乘积的最大值。

    Solution

    很容易想到并查集,将 (i) 从大到小处理,每到一个新的 (i) ,就将所有 (h[j]=i)(j-1)(j) 两个后缀所在集合合并,维护每个集合的大小以及其中最最大次大最小次小。注意判断一下边界情况。

    但是我非常懒惰,所以用了 set + 启发式合并。

    // How many different substrings are there in the main string
    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    int n,m=256,sa[1000005],y[1000005],u[1000005],v[1000005],o[1000005];
    int r[1000005],h[1000005],T,val[1000005],f[300005];
    char str[1000005];
    long long ans1,ans2=-1e18;
    vector <int> pos[300005];
    multiset <int> st[300005];
    
    int mix(multiset <int> &a, multiset <int> &b)
    {
        if(a.size()>b.size())
        {
            a.insert(b.begin(),b.end());
            return 0;
        }
        else
        {
            b.insert(a.begin(),a.end());
            return 1;
        }
    }
    
    int getans2(multiset <int> &s)
    {
        if(s.size()<2) return 0;
        else
        {
            multiset<int>::iterator it1,it2,it3,it4;
            it1=s.begin();
            it2=it1;
            ++it2;
            it3=s.end();
            --it3;
            it4=it3;
            --it4;
            return max((*it1)*(*it2), (*it3)*(*it4));
        }
    }
    
    int find(int x)
    {
        return f[x]==x?x:f[x]=find(f[x]);
    }
    void merge(int i,int j)
    {
        if(find(i)!=find(j))
        {
            ans1+=(int)(st[find(i)].size())*(int)(st[find(j)].size());
            int fg=mix(st[find(i)],st[find(j)]);
            if(fg) f[find(i)]=find(j);
            else f[find(j)]=find(i);
            ans2=max(ans2,getans2(st[find(i)]));
        }
    }
    
    signed main()
    {
        scanf("%lld",&n);
        scanf("%s",str+1);
        for(int i=1; i<=n; i++) scanf("%lld",&val[i]);
    
        for(int i=1; i<=n; i++) u[str[i]]++;
        for(int i=1; i<=m; i++) u[i]+=u[i-1];
        for(int i=n; i>=1; i--) sa[u[str[i]]--]=i;
        r[sa[1]]=1;
        for(int i=2; i<=n; i++) r[sa[i]]=r[sa[i-1]]+(str[sa[i]]!=str[sa[i-1]]);
    
        for(int l=1; r[sa[n]]<n; l<<=1)
        {
            memset(u,0,sizeof u);
            memset(v,0,sizeof v);
            memcpy(o,r,sizeof r);
            for(int i=1; i<=n; i++) u[r[i]]++, v[r[i+l]]++;
            for(int i=1; i<=n; i++) u[i]+=u[i-1], v[i]+=v[i-1];
            for(int i=n; i>=1; i--) y[v[r[i+l]]--]=i;
            for(int i=n; i>=1; i--) sa[u[r[y[i]]]--]=y[i];
            r[sa[1]]=1;
            for(int i=2; i<=n; i++) r[sa[i]]=r[sa[i-1]]+((o[sa[i]]!=o[sa[i-1]])||(o[sa[i]+l]!=o[sa[i-1]+l]));
        }
        {
            int i,j,k=0;
            for(int i=1; i<=n; h[r[i++]]=k)
                for(k?k--:0,j=sa[r[i]-1]; str[i+k]==str[j+k]; k++);
        }
    
        for(int i=2; i<=n; i++)
        {
            pos[h[i]].push_back(i);
        }
        for(int i=1; i<=n; i++) st[i].insert(val[sa[i]]);
        for(int i=1; i<=n; i++) f[i]=i;
        vector <int> a1,a2;
        for(int i=n-1; i>=0; --i)
        {
            for(int j=0; j<pos[i].size(); j++)
            {
                merge(pos[i][j],pos[i][j]-1);
            }
            a1.push_back(ans1);
            a2.push_back(ans2);
        }
        for(int i=n-1; i>=0; --i) printf("%lld %lld
    ",a1[i],(a2[i]<-9e17?0:a2[i]));
    }
    
  • 相关阅读:
    Git 之 git原理简介
    Django 之 富文本编辑器-tinymce
    Django 之 Ajax
    Django 之 分页
    Django 之 用redis存储session
    Django 之 自定义中间件
    python 之 多线程、多进程代码
    反转字符串
    青蛙跳台阶
    pandas 之 concat
  • 原文地址:https://www.cnblogs.com/mollnn/p/11762266.html
Copyright © 2011-2022 走看看