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
    在日渐沉没的世界里,我发现了你。
  • 相关阅读:
    'IDataObject': ambiguous symbol的解决方法
    捕获windows系统的sleep或hibernate状态
    CallingConvention理解
    Exception from HRESULT: 0x8001010D (RPC_E_CANTCALLOUT_ININPUTSYNCCALL))
    .Net Managed C++如何获取当前线程id和当前进程id
    div垂直居中于div中
    父级是relative,子级为absolute的情况下,子级宽度自适应
    background-img高度固定,图片自适应
    如何让两个input紧挨着.
    C# 调用百度短链接api
  • 原文地址:https://www.cnblogs.com/mastervan/p/14594261.html
Copyright © 2011-2022 走看看