• bzoj4199: [Noi2015]品酒大会


    http://www.lydsy.com/JudgeOnline/problem.php?id=4199

      给定一个字符串S,设Si表示S从i开始的的后缀。若Si, Sj存在长度为r的公共前缀,则称i和j是r相似的。每个后缀有一个价值vi,一对后缀Si与Sj的价值是vi*vj。对于每个r=0~n-1,统计有多少对r相似的后缀,以及r相似的后缀的最大价值(n≤300000)。

      我们先后缀排序,并得到height值。我们考虑动态维护集合,保证集合内的答案已经统计过了,在合并的时候更新集合与集合间的答案即可。初始每个后缀自己构成一个大小为1的集合。按height从大到小枚举每个后缀,将rank为i的后缀与rank为i-1的后缀合并,他们更新的r即为当前的height。更新答案并用并查集维护集合即可。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=300015;
    typedef long long int64;
    typedef pair<int,int> PII;
    int n,v[maxn];char s[maxn];
    struct Tsuffix_array{
        int sum[maxn],sa[maxn],rank[maxn],tsa[maxn],trank[maxn];
        bool cmp(int i,int j,int l){
            if (i+l>n||j+l>n) return 0;
            return rank[i]==rank[j]&&rank[i+l]==rank[j+l];
        }
        void suffix_sort(){
            int m=255,p,i,j;
            for (i=0;i<=m;++i) sum[i]=0;
            for (i=1;i<=n;++i) ++sum[rank[i]=s[i]];
            for (i=1;i<=m;++i) sum[i]+=sum[i-1];
            for (i=n;i>=1;--i) sa[sum[rank[i]]--]=i;
            for (j=1,p=0;p<n;j<<=1,m=p){
                for (p=0,i=n-j+1;i<=n;++i) tsa[++p]=i;
                for (i=1;i<=n;++i) if (sa[i]>j) tsa[++p]=sa[i]-j;
                for (i=0;i<=m;++i) sum[i]=0;
                for (i=1;i<=n;++i) ++sum[rank[tsa[i]]];
                for (i=1;i<=m;++i) sum[i]+=sum[i-1];
                for (i=n;i>=1;--i) sa[sum[rank[tsa[i]]]--]=tsa[i];
                for (p=trank[sa[1]]=1,i=2;i<=n;++i) trank[sa[i]]=cmp(sa[i],sa[i-1],j)?p:++p;
                memcpy(rank,trank,sizeof(int)*(n+1));
            }
        }
        int height[maxn];
        void get_height(){
            for (int h=0,i=1;i<=n;++i){
                if (rank[i]==1) continue;
                for (h?--h:0;s[i+h]==s[sa[rank[i]-1]+h];++h);
                height[rank[i]]=h; 
            }
        }
        int fa[maxn],siz[maxn],fmx[maxn],fmn[maxn];
        int find(int u){return u==fa[u]?u:fa[u]=find(fa[u]);}
        void merge(int x,int y){
            if (siz[x]<siz[y]) swap(x,y);
            fa[y]=x;siz[x]+=siz[y];
            fmx[x]=max(fmx[x],fmx[y]);
            fmn[x]=min(fmn[x],fmn[y]);
        }
        PII t[maxn];
        int64 ans1[maxn],ans2[maxn];
        void get_ans(){
            for (int i=2;i<=n;++i) t[i-1]=make_pair(height[i],i);
            for (int i=1;i<=n;++i) fmx[rank[i]]=fmn[rank[i]]=v[i];
            sort(t+1,t+n,greater<PII>());memset(ans2,200,sizeof(ans2));
            for (int i=1;i<=n;++i){fa[i]=i;siz[i]=1;}
            for (int i=1;i<=n-1;++i){
                int x=find(t[i].second-1),y=find(t[i].second);
                ans1[t[i].first]+=1ll*siz[x]*siz[y];
                ans2[t[i].first]=max(ans2[t[i].first],1ll*fmx[x]*fmx[y]);
                ans2[t[i].first]=max(ans2[t[i].first],1ll*fmn[x]*fmx[y]);
                ans2[t[i].first]=max(ans2[t[i].first],1ll*fmx[x]*fmn[y]);
                ans2[t[i].first]=max(ans2[t[i].first],1ll*fmn[x]*fmn[y]);
                merge(x,y);
            }
            for (int i=n-1;i>=0;--i){
                ans1[i]+=ans1[i+1];
                ans2[i]=max(ans2[i],ans2[i+1]);
            }
            for (int i=0;i<=n-1;++i)
                printf("%lld %lld
    ",ans1[i],!ans1[i]?0:ans2[i]);
        }
    }SA;
    void init(){
        scanf("%d%s",&n,s+1);
        for (int i=1;i<=n;++i) scanf("%d",&v[i]);
    }
    void work(){
        SA.suffix_sort();
        SA.get_height();
        SA.get_ans();
    }
    int main(){
        init();
        work(); 
        return 0;
    }
    my code
  • 相关阅读:
    JVM致命错误日志(hs_err_pid.log)分析
    JVM调优-命令大全(jps jstat jmap jhat jstack jinfo
    GC日志分析详解
    简单的学习,实现,领域事件,事件存储,事件溯源
    学习DDD的初步尝试,从最基础的开始,业务介绍,划分限界上下文 ,建立模型
    .Net Core + DDD基础分层 + 项目基本框架 + 个人总结
    第三节:使用Log4net和过滤器记录异常信息,返回异常给前端
    从一层到多层架构的学习笔记
    学习服务之间的调用,三个方法的演化
    .Net Core3.0 WEB API 中使用FluentValidation验证,实现批量注入
  • 原文地址:https://www.cnblogs.com/iamCYY/p/4727309.html
Copyright © 2020-2023  润新知