• LIS反链


    链接

    直线上有n座山峰,第i座的高度为hi。从某座山峰上放飞一架纸飞机,它可以从左往右依次经过一系列高度严格递减的山头。
    假设五座山峰的高度依次是3,4,3,2,1。从第一座山峰上放飞的纸飞机可以依次经过第一、四、五座山峰,但不能经过第二、三座山峰。
    对于每座山峰,求出要经过除这座山峰外的每座山峰,至少需要放飞多少纸飞机。(每架纸飞机的起点可以不同)
    输入描述:
    第一行包括一个正整数n。
    第二行包括n个正整数,第i个数表示第i座山峰的高度hi。
    输出描述:
    输出一行,包括n个用空格隔开的正整数,第i个数表示除去第i座山峰的答案。
    输入

    5
    2 4 3 1 5
    

    输出

    2 3 3 3 2
    

    即求除去i之后反链的长度。
    设x[i]:以i为结尾的最长非降子序列长度
    设y[i]:以i为开头的最长非降子序列长度
    则包括a[i]的最长反链长度为x[i]+y[i]-1
    如果该长度不等于a的最长反链长度len,则除去a[i]后反链长度不变,答案是len
    否则

    1. 如果除去a[i]后反链长度-1的话,答案就是len-1
    2. 如果除去a[i]后反链长度不变,答案就是len

    记录所有x[i]+y[i]-1== len时x[i]出现的次数,
    如果x[i]出现次数大于1次,说明有另一条不包括i的最长反链:
    设i、j都满足x[k]+y[k]-1=len且x[i]==x[j],要么j<i且链y[j]里不可能包括a[i](如果包括则y[j]>y[i]),要么i<j且链x[i]里不可能包括a[i](如果包括则x[j]>x[i]),所以,x[j]+y[j]-1这条反链不包括a[i],所以除去a[i]后还有另一条最长反链。
    计算y时相当于反着计算x。

    #include<bits/stdc++.h>
    using namespace std;
    char buf[1<<20],*_=buf,*__=buf;
    #define gc() (_==__&&(__=(_=buf)+fread(buf,1,1<<20,stdin),_==__)?EOF:*_++)
    #define TT template<class T>inline
    TT bool read(T &x){
        x=0;char c=gc();bool f=0;
        while(c<48||c>57){if(c==EOF)return 0;f^=(c=='-'),c=gc();}
        while(47<c&&c<58)x=(x<<3)+(x<<1)+(c^48),c=gc();
        if(f)x=-x;return 1;
    }
    TT bool read(T&a,T&b){return read(a)&&read(b);}
    TT bool read(T&a,T&b,T&c){return read(a)&&read(b)&&read(c);}
    typedef long long ll;
    const ll MAXN=1e6+8,mod=1e9+7,inf=0x3f3f3f3f;
    int n,a[MAXN],k[MAXN],l;
    int x[MAXN],y[MAXN],cnt[MAXN];
    int main() {
        read(n);
        for(int i=0;i<n;++i)read(a[i]);
        k[0]=a[0],l=1,x[0]=1;
        for(int i=1,j;i<n;++i){
            if(a[i]>=k[l-1])k[l]=a[i],x[i]=++l;
            else{
                j=upper_bound(k,k+l,a[i])-k;
                k[j]=a[i];
                x[i]=j+1;
            }
        }
        k[0]=-a[n-1],l=1,y[n-1]=1;
        for(int i=n-2,j;i>=0;--i){
            if(a[i]<=-k[l-1])k[l]=-a[i],y[i]=++l;
            else{
                j=upper_bound(k,k+l,-a[i])-k;
                k[j]=-a[i];
                y[i]=j+1;
            }
        }
        for(int i=0;i<n;++i){
            if(x[i]+y[i]-1==l)cnt[x[i]]++;
        }
        for(int i=0;i<n;++i){
            if(x[i]+y[i]-1==l){
                if(cnt[x[i]]>1)printf("%d ",l);
                else printf("%d ",l-1);
            }else printf("%d ",l);
        }
        return 0;
    }
    
  • 相关阅读:
    Docker从入门到精通(四)——常用命令
    Docker从入门到精通(二)——安装Docker
    Docker从入门到精通(一)——初识
    Java设计模式之(十三)——模板方法模式
    Java设计模式之(十四)——策略模式
    Docker从入门到精通(七)——容器数据共享
    YCFramework版本更新:V1.0.2
    YCFramework版本更新:V1.0.3
    我的分布式微服务框架:YCFramework
    mysql 多表多字段报表填充查询
  • 原文地址:https://www.cnblogs.com/foursmonth/p/14161965.html
Copyright © 2020-2023  润新知