• NOI2015 品酒大会


    先放个传送门

    后缀数组模板题

    如果(p,q)(r)相似的,相当于(p,q)有一个长度为(r)(lcp)
    考虑把(SA)(Height)建出来之后,让(Height)从大到小排序.然后从大到小做(因为两杯(r)相似的酒肯定是(0,1,2...r)相似的).用并查集维护每个连通块的(size,max,min).如果要合并(p,q),那么方案加上(size[p]*size[q]),(Ans=max(Ans,Max[p]*Max[q],Min[p]*Min[q]))即可.
    于是我们可以在(O(nlog n))的优秀复杂度内完成此题.

    代码如下(人傻自带大常数)

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<vector>
    #define N (1000010)
    #define inf (0x7f7f7f7f)
    #define rg register int
    #define Label puts("NAIVE")
    #define spa print(' ')
    #define ent print('
    ')
    #define rand() (((rand())<<(15))^(rand()))
    typedef long double ld;
    typedef long long LL;
    typedef unsigned long long ull;
    using namespace std;
    struct Union{int x,y,pos;}a[N],b[N],c[N];
    struct edge{int l,r,v;}e[N];
    char s[N]; bool flag; LL ans,cnt,outa[N],outc[N];
    int n,suffix[N],rk[N],sa[N],rec[N],Height[N],M,w[N];
    int mx[N],siz[N],fa[N],mn[N];
    bool cmp(edge A,edge B){return A.v>B.v;}
    void jipai(){
        memset(rec,0,sizeof(rec));
        for(int i=1;i<=n;i++)rec[a[i].y]++;
        for(int i=1;i<=M;i++)rec[i]=rec[i-1]+rec[i];
        for(int i=n;i;i--)b[rec[a[i].y]]=a[i],rec[a[i].y]--;
        memset(rec,0,sizeof(rec));
        for(int i=1;i<=n;i++)rec[b[i].x]++;
        for(int i=1;i<=M;i++)rec[i]=rec[i-1]+rec[i];
        for(int i=n;i;i--)c[rec[b[i].x]]=b[i],rec[b[i].x]--;
        int p=0;
        for(int i=1;i<=n;i++){
            if(c[i].x!=c[i-1].x||c[i].y!=c[i-1].y)p++;
            rk[c[i].pos]=a[c[i].pos].x=p;
            if(p==n)flag=1; M=max(M,p);
        }
    }
    void get_sa(){
        scanf("%d%s",&n,s+1),M=127;
        for(int i=1;i<=n;i++)scanf("%d",&w[i]);
        for(int i=1;i<=n;i++)
        a[i].x=s[i]-'0'+1,a[i].y=0,a[i].pos=i;
        jipai();
        for(int i=1;i<=n;i++)a[i].x=rk[i];
        for(int k=1;k<=n;k*=2){
            for(int i=1;i<=n;i++)
            if(i+k>n)a[i].y=0;else a[i].y=rk[i+k];
            jipai();
            if(flag)break;
        }
        for(int i=1;i<=n;i++)sa[rk[i]]=i;
    }
    void get_height(){
        int x,y=0;
        for(int i=1;i<=n;Height[rk[i++]]=y)
        for(y=y?y-1:y,x=sa[rk[i]-1];s[i+y]==s[x+y];y++);
    }
    int ask(int x){
        return (fa[x]==x)?x:(fa[x]=ask(fa[x]));
    }
    void unite(int x,int y){
        int p=ask(x),q=ask(y);
        fa[q]=p,cnt+=((LL)siz[p]*(LL)siz[q]);
        ans=max(ans,max((LL)mx[p]*(LL)mx[q],(LL)mn[p]*(LL)mn[q]));
        mx[p]=max(mx[p],mx[q]),mn[p]=min(mn[p],mn[q]),siz[p]+=siz[q];
    }
    int main(){
        get_sa(),get_height();
        for(int i=1;i<=n;i++)fa[i]=i,mx[i]=mn[i]=w[i],siz[i]=1;
        for(int i=2;i<=n;i++)e[i-1]=(edge){sa[i-1],sa[i],Height[i]};
        sort(e+1,e+n,cmp),ans=-1e18-1;
        for(int i=n-1,j=1;i>=0;i--){
            for(;e[j].v==i;j++)unite(e[j].l,e[j].r);
            outa[i]=(cnt>0)?ans:0,outc[i]=cnt;
        }
        for(int i=0;i<n;i++)
        printf("%lld %lld
    ",outc[i],outa[i]);
    }
    
  • 相关阅读:
    ICMPv6 Type 和 rfc
    Redis学习
    Vue学习(一)
    《一线架构师实践指南》读后感(五)
    《一线架构师实践指南》读后感(四)
    Stream流
    泛型
    《架构漫谈》读后感
    《一线架构师实践指南》读后感(三)
    《一线架构师实践指南》读后感(二)
  • 原文地址:https://www.cnblogs.com/Romeolong/p/10056786.html
Copyright © 2020-2023  润新知