• [bzoj5158][Tjoi2014]Alice and Bob


    好羞愧啊最近一直在刷水。。。

    题意:给定序列$c$的$a_i$,构造出一个序列$c$使得$sum b_i$最大。

    其中$a_i$表示以$c_i$结尾的最长上升子序列长度,$b_i$表示以$c_i$为开头的最长下降子序列长度。

    首先$a_i = x$一定是从一个$a_j = x-1$转移而来的。这里让$a_i$从所有$a_j = x-1$的$a_j$里$c_j$最小的转移而来,一定不会有更优的转移。

    因为这样它还可以和其它$a_j$做出至少1的贡献。那么我们由$i$向$j$连边。这样会形成一棵以0为根的树,后连边的点先遍历,令$c_j $等于dfs序。这样得到的序列就可以满足题意。求一遍$b$就行了。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=100010;
    inline int read(){
        int r=0,c=getchar();
        while(!isdigit(c))c=getchar();
        while(isdigit(c))
        r=r*10+c-'0',c=getchar();
        return r;
    }
    struct Edge{
        int to,nxt;
    }e[N*2];
    int head[N],cnt=1;
    void add(int u,int v){
        e[cnt]=(Edge){v,head[u]};
        head[u]=cnt++;
    }
    int a[N],las[N],n,dc;
    void dfs(int u){
        a[u]=++dc;
        for(int i=head[u];i;i=e[i].nxt)
        dfs(e[i].to);
    }
    int b[N],c[N];
    void upd(int x,int v){
        for(int i=x;i<=n;i+=i&-i)
        c[i]=max(c[i],v);
    }
    int ask(int x){
        int ret=0;
        for(int i=x;i;i-=i&-i)
        ret=max(ret,c[i]);
        return ret;
    }
    int main(){
        n=read();
        for(int i=1;i<=n;i++){
            int x=read();
            add(las[x-1],i);
            las[x]=i;
        }
        dfs(0);
        long long ans=0;
        for(int i=n;i;i--){
            b[i]=ask(a[i]-1)+1;
            ans+=1ll*b[i];
            upd(a[i],b[i]);
        }
        cout<<ans;
    }
  • 相关阅读:
    Scrum会议5
    小组项目alpha发布的评价
    第二阶段冲刺记录三
    第二阶段冲刺记录二
    第13周学习进度
    第二阶段冲刺记录1
    《人月神话》阅读笔记01
    第12周学习进度
    意见汇总
    双人结对,四则运算(三阶段)
  • 原文地址:https://www.cnblogs.com/orzzz/p/8444149.html
Copyright © 2020-2023  润新知