zoukankan      html  css  js  c++  java
  • [后缀数组][并查集]luogu P2178 [NOI2015] 品酒大会

    题面

    https://www.luogu.com.cn/problem/P2178

    分析

    对酒名用处理出height,按照height从大到小枚举(排除 1 ),由于 LCP(i,j)=min(LCP(k,k-1))(k>i) ,所以在 height 单调递减的情况下,可以用用并查集合并 i 和 i-1 ,则当前 height[i] 相似的字符串有 size[Father(i)]*size[Father(i-1)] 个

    同时记录每个集合的最大最小值,再计算相互相乘的的结果记录到 height[i] 相似的最大美味值中

    最后不要忘记 r 相似意味着 0~r-1 相似,所以方案数取后缀和,最大美味值取后缀最大值

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    const ll Inf=1e18+1;
    const int N=3e5+10;
    int n;
    int sa[N],rk[N],height[N],x[N],y[N],c[N];
    int f[N],sz[N],ord[N];
    ll sols[N],mxyum[N],ans[N],a[N],mx[N],mn[N];
    char s[N];
    
    int Get_F(int x) {return x==f[x]?x:f[x]=Get_F(f[x]);}
    
    void Suffix_Array(int n,char *s,int *sa,int *rk) {
        int m='z',cnt;
        for (int i=0;i<=m;i++) c[i]=0;
        for (int i=1;i<=n;i++) c[x[i]=s[i]]++;
        for (int i=1;i<=m;i++) c[i]+=c[i-1];
        for (int i=n;i;i--) sa[c[x[i]]--]=i;
        for (int j=1;j<=n;j<<=1) {
            cnt=0;
            for (int i=n-j+1;i<=n;i++) y[++cnt]=i;
            for (int i=1;i<=n;i++) if (sa[i]>j) y[++cnt]=sa[i]-j;
            for (int i=0;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]]=cnt=1;
            for (int i=2;i<=n;i++) x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[min(sa[i]+j,n+1)]==y[min(sa[i-1]+j,n+1)]?cnt:++cnt);
            m=cnt;if (m==n) break;
        }
        for (int i=1;i<=n;i++) rk[sa[i]]=i;
    }
    
    void Get_Height(int n,int *sa,int *rk,int *height) {
        int z=0;
        for (int i=1;i<=n;i++) {
            if (rk[i]==1) {height[rk[i]]=0;continue;}
            if (z) z--;
            while (i+z<=n&&sa[rk[i]-1]+z<=n&&s[i+z]==s[sa[rk[i]-1]+z]) z++;
            height[rk[i]]=z;
        }
    }
    
    bool CMP(int a,int b) {return height[a]>height[b];}
    
    int main() {
        scanf("%d",&n);
        scanf("%s",s+1);
        Suffix_Array(n,s,sa,rk);Get_Height(n,sa,rk,height);
        for (int i=1;i<=n;i++) scanf("%lld",&a[i]),mx[i]=mn[i]=a[i],sz[f[i]=ord[i]=i]=1,mxyum[i]=ans[i]=-Inf;
        sort(ord+1,ord+n+1,CMP);
        for (int i=1,x,y;i<=n;i++)
            if (ord[i]!=1) {
                x=Get_F(sa[ord[i]]);y=Get_F(sa[ord[i]-1]);f[y]=x;
                sols[height[ord[i]]]+=1ll*sz[x]*sz[y];sz[x]+=sz[y];
                ans[height[ord[i]]]=max(ans[height[ord[i]]],mxyum[x]=max(max(mxyum[x],mxyum[y]),max(max(mx[x]*mx[y],mx[x]*mn[y]),max(mn[x]*mx[y],mn[x]*mn[y]))));
                mx[x]=max(mx[x],mx[y]);mn[x]=min(mn[x],mn[y]);
            }
        for (int i=n-1;~i;i--) sols[i]+=sols[i+1],ans[i]=max(ans[i],ans[i+1]);
        for (int i=0;i<n;i++) printf("%lld %lld
    ",sols[i],(sols[i]>0)*ans[i]);
    }
    View Code
    在日渐沉没的世界里,我发现了你。
  • 相关阅读:
    12月12日总结
    练习:请用索引取出下面list的指定元素:
    练习:小明身高1.75,体重80.5kg。请根据BMI公式(体重除以身高的平方)帮小明计算他的BMI指数,并根据BMI指数:
    练习:请利用循环依次对list中的每个名字打印出Hello, xxx!:
    练习:学员管理系统
    练习:请修改列表生成式,通过添加if语句保证列表生成式能正确地执行
    CF1067D Computer Game
    高等数学第三章
    CF755G PolandBall and Many Other Balls
    TS泛型工具
  • 原文地址:https://www.cnblogs.com/mastervan/p/14594261.html
Copyright © 2011-2022 走看看