• [BZOJ]4199: [Noi2015]品酒大会(后缀数组+笛卡尔树)


    Time Limit: 10 Sec  Memory Limit: 512 MB

    Description

    Input

    Output

    Sample Input

    10
    ponoiiipoi
    2 1 4 7 4 8 3 6 4 7

    Sample Output

    45 56
    10 56
    3 32
    0 0
    0 0
    0 0
    0 0
    0 0
    0 0
    0 0

    HINT

     

    Solution

      先求出后缀数组,两个后缀的最长公共前缀是它们之间height的最小值,对height建笛卡尔树,树上维护最大最小值即可。

    Code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    inline int read()
    {
        int x,f=1;char c;
        while((c=getchar())<'0'||c>'9')if(c=='-')f=0;
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=x*10+c-'0';
        return f?x:-x;
    }
    #define MN 300000
    int v[MN+5],ar[MN*4+10],*sa=ar,*nsa=sa+MN+2,*rk=nsa+MN+2,*nrk=rk+MN+2,h[MN+5];
    int a[MN+5],z[MN+5],zn,lc[MN+5],rc[MN+5],sz[MN+5],mx[MN+5],mn[MN+5];
    ll f1[MN+5],f2[MN+5];
    char s[MN+5];
    void dfs(int x)
    {
        if(!x)return;
        int l=lc[x],r=rc[x];
        dfs(l);dfs(r);
        if(!l)l=MN+1,sz[l]=1,mx[l]=mn[l]=a[sa[x-1]];
        if(!r)r=MN+2,sz[r]=1,mx[r]=mn[r]=a[sa[x]];
        f1[h[x]]+=1LL*sz[l]*sz[r];
        f2[h[x]]=max(f2[h[x]],max(max(1LL*mn[l]*mn[r],1LL*mn[l]*mx[r]),
                                  max(1LL*mx[l]*mn[r],1LL*mx[l]*mx[r])));
        sz[x]=sz[l]+sz[r];
        mn[x]=min(mn[l],mn[r]);
        mx[x]=max(mx[l],mx[r]);
    }
    int main()
    {
        int n=read(),l,i,x;
        scanf("%s",s+1);
        for(i=1;i<=n;++i)a[i]=read();
        for(i=1;i<=n;++i)++v[s[i]];
        for(i='a';i<='z';++i)v[i]+=v[i-1];
        for(i=1;i<=n;++i)sa[v[s[i]]--]=i;
        for(i=1;i<=n;++i)rk[sa[i]]=rk[sa[i-1]]+(s[sa[i]]!=s[sa[i-1]]);
        for(l=1;l<n;l<<=1,swap(sa,nsa),swap(rk,nrk))
        {
            for(i=1;i<=n;++i)v[rk[sa[i]]]=i;
            for(i=n;i;--i)if(sa[i]>l)nsa[v[rk[sa[i]-l]]--]=sa[i]-l;
            for(i=0;i<l;++i)nsa[v[rk[n-i]]--]=n-i;
            for(i=1;i<=n;++i)nrk[nsa[i]]=nrk[nsa[i-1]]+(rk[nsa[i]]!=rk[nsa[i-1]]||rk[nsa[i]+l]!=rk[nsa[i-1]+l]);
        }
        for(i=1,l=0;i<=n;++i,l?--l:0)
            if(rk[i]>1){for(x=sa[rk[i]-1];s[i+l]==s[x+l];++l);h[rk[i]]=l;}
        for(i=2;i<=n;++i)
        {
            while(zn&&h[i]<h[z[zn]])lc[i]=z[zn--];
            rc[z[zn]]=i;z[++zn]=i;
        }
        memset(f2,200,sizeof(f2));
        dfs(z[1]);
        for(i=n;i--;)f1[i]+=f1[i+1],f2[i]=max(f2[i],f2[i+1]);
        for(i=0;i<n;++i)printf("%lld %lld
    ",f1[i],f1[i]?f2[i]:0);
    }
  • 相关阅读:
    微信分享链接出现config:invalid signature错误的解决方法
    微信开发,分享部分出现的问题
    thinkphp 3.2 去除调试模式后报错,怎么解决
    MySQL添加新用户、为用户创建数据库、为新用户分配权限
    xshell工具source导入几个G的数据库
    thinkphp5引入公共部分header、footer等
    用样本估计总体
    随机抽样
    平面几何相关定理
    直线和曲线相切,曲线和曲线相切
  • 原文地址:https://www.cnblogs.com/ditoly/p/BZOJ4199.html
Copyright © 2020-2023  润新知