• BZOJ 4199 品酒大会


    以前一直听说什么后缀数组height合并之类的

    表示我这种后缀数组都敲不熟的蒟蒻怎么会写

    但是做了做觉得还是很简单的嘛

    这个题是有两问的,第一问是求LCP>=R的后缀对有多少个

    这个就是AHOI2013 差异 稍微变个形啦

    直接逆序建后缀自动机,在parent树上做一个很简单的树P就可以了

    因为对于现在parent树而言,任意两点的LCP等于两点在树上的LCA的len

    到这里,其实我们已经可以拿到70分了

    一部分数据暴力,一部分数据LCP<10也可以暴力,还有一部分数据ai相等,等价于只用求第一问

    之后我们考虑第二问,对于当前的parent树而言,等价于求parent树上两个叶节点乘积的最大值

    又因为考虑到ai可能是负数,所以我们只需要记录最大值,次大值,最小值,次小值就可以了

    这也是一个非常简单的树P

    UPD:题目可以去UOJ去看

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cstdlib>
    #include<algorithm>
    using namespace std;
     
    typedef long long LL;
    const int maxn=600010;
    const LL oo=1LL<<62;
    int n,cnt,la;
    int a[maxn];
    char s[maxn];
    struct Node{
        int next[26];
        int len,link;
    }st[maxn];
    int t[maxn],b[maxn];
    LL ans1[maxn],ans2[maxn];
    LL mx[maxn],cmx[maxn];
    LL mn[maxn],cmn[maxn];
    LL sum[maxn];
     
    void read(int &num){
        num=0;int f=1;char ch=getchar();
        while(ch<'!')ch=getchar();
        if(ch=='-')f=-1,ch=getchar();
        while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar();
        num*=f;
    }
    void init(){
        cnt=la=0;
        st[0].link=-1;
    }
    void add(int c){
        int cur=++cnt;
        st[cur].len=st[la].len+1;
        int p;
        for(p=la;p!=-1&&st[p].next[c]==0;p=st[p].link)st[p].next[c]=cur;
        if(p==-1)st[cur].link=0;
        else{
            int q=st[p].next[c];
            if(st[q].len==st[p].len+1)st[cur].link=q;
            else{
                int clone=++cnt;
                st[clone]=st[q];
                st[clone].len=st[p].len+1;
                for(;p!=-1&&st[p].next[c]==q;p=st[p].link)st[p].next[c]=clone;
                st[cur].link=st[q].link=clone;
            }
        }la=cur;
    }
     
     
    int main(){
        read(n);scanf("%s",s+1);init();
        for(int i=1;i<=n;++i)read(a[i]);
        for(int i=n;i>=1;--i)add(s[i]-'a');
        for(int i=0;i<=cnt;++i){
            mx[i]=-oo;cmx[i]=-oo;
            mn[i]=oo;cmn[i]=oo;
        }
        int now=0;
        for(int i=n;i>=1;--i){
            int id=s[i]-'a';
            now=st[now].next[id];
            sum[now]++;
            mx[now]=a[i];mn[now]=a[i];
        }
        for(int i=0;i<=cnt;++i)t[st[i].len]++;
        for(int i=1;i<=n;++i)t[i]+=t[i-1];
        for(int i=0;i<=cnt;++i)b[--t[st[i].len]]=i;
        for(int i=0;i<=n;++i)ans2[i]=-oo;
        for(int i=cnt;i>=0;--i){
            int v=b[i],u=st[v].link,R=st[v].len,L=st[u].len;
             
            LL tmp=-oo;
            if(cmx[v]!=-oo)tmp=max(tmp,mx[v]*cmx[v]);
            if(cmn[v]!=oo)tmp=max(tmp,mn[v]*cmn[v]);
            if(tmp!=-oo)ans2[R]=max(ans2[R],tmp);
             
            ans1[L]+=sum[u]*sum[v];
             
            sum[u]=sum[u]+sum[v];
             
            if(mx[v]>=mx[u]){cmx[u]=mx[u];mx[u]=mx[v];}
            else if(mx[v]>cmx[u])cmx[u]=mx[v];
             
            if(mn[v]<=mn[u]){cmn[u]=mn[u];mn[u]=mn[v];}
            else if(mn[v]<cmn[u])cmn[u]=mn[v];
        }
        for(int i=n-1;i>=0;--i)ans1[i]+=ans1[i+1];
        for(int i=n-1;i>=0;--i)ans2[i]=max(ans2[i],ans2[i+1]);
        for(int i=0;i<n;++i){
            if(!ans1[i])ans2[i]=0;
            printf("%lld %lld
    ",ans1[i],ans2[i]);
        }return 0;
    }
    

      

  • 相关阅读:
    hadoop机架感知
    Ajax请求结果的缓存
    Blocks语法
    CentOS yum 源的配置与使用
    .NET三层架构开发初步
    Mac技巧合集第一期
    Fine Uploader文件上传组件
    WCF 系列文章
    http权威指南读书笔记
    WCF Service Hosting的线程关联性Mono实现比.NET统一?
  • 原文地址:https://www.cnblogs.com/joyouth/p/5366396.html
Copyright © 2020-2023  润新知