LIS

LIS(Longest Increasing Subsequence)即最长上升子序列

给定一个序列,LIS是指其所有上升子序列中最长的一个

举个例子a={100,98,300,385,200,166}其最长上升子序列为{100,300,385}

朴素dp求法O(n*n)

算法描述

f[i]指以i为起点的LIS长度(视情况而定)。枚举起点,起点之后的原序列,如果a[j]>a[i]则f[i]可能是以j为起点的LIS+1,即f[i]=max(f[i],f[j]+1)。此处pre数组用来记录前驱,当前的i是由j转移过来的。

由于f[i]要由f[i+1---n]更新而来,所以枚举起点要倒序

Code
for(int i=n;i>0;--i){
    for(int j=i;j<=n;++j){
        if(a[j]>a[i]){
            if(f[i]<f[j]+1){
                pre[i]=j;f[i]=f[j]+1;
            }
        }
    }
}

贪心+二分查找O(n*log(n))

算法描述

LIS数组记录可能的LIS,len表示LIS长度。扫描整个数组,如果a[i]大于LIS[len],则在末尾插入a[i];否则就在LIS中找到第一个比a[i]大的数,用a[i]将其替换,此处用到了stl upper_bound();

模拟

a={100,98,300,385,200,166}

i=1 LIS={100}

i=2 LIS={98}这里把100替换是为了让更多的数放进来,体现了贪心思想

i=3 LIS={98,300}

i=4 LIS={98,300,385}

i=5 LIS={98,200,385}

i=6 LIS={98,166,385}

很显然,这里求出的LIS是错误的,但是其保证了单调性,len是正确的

for(int i=1;i<=n;++i){
        if(a[i]>LIS[len]){
            LIS[++len]=a[i];
        }
        else{
            int pos=upper_bound(LIS+1,LIS+len+1,a[i])-LIS;
            LIS[pos]=a[i];//LIS不是正确的序列,但长度是正确的
        }
    }   

关于upper_bound()和lower_bound()

upper_bound(start,end+1,data)。start为查找范围左端点的指针,end为查找范围右端点的指针,upper_bound会返回范围中第一个大于data的数的指针,如果找不到就返回end

lower_bound(start,end+1,data)。start为查找范围左端点的指针,end为查找范围右端点的指针,lower_bound会返回范围中第一个大于等于data的数的指针,如果找不到就返回end

重载

upper_bound(start,end+1,data,greater())

upper_bound会返回范围中第一个小于data的数的指针,如果找不到就返回end+1

lower_bound(start,end+1,data,greater())

lower_bound会返回范围中第一个小于等于data的数的指针,如果找不到就返回end+1

在结构体中的使用
重载一下小于号就行了

update 2022 1 25

树状数组维护LIS

x是原数组内某个值

c[x]定义为以x结尾的LIS长度

本质上是O(n^2)做法的优化,也就是说可以记录路径

代码可能是错的,退役了,先鸽着

void update(int x,int data){
    for(int i=x;i<=n;i+=lowbit(x)){
        if(c[x]+1>c[i]){
            c[i]=c[x]+1;
            pre[i]=x;
        }
    }
}
int query(int x){
    int res=0;
    for(int i=x;i;i-=lowbit(x)){
        res=max(res,c[i]);
    }
    return res;
}
void work(){
     n=read();
     for(int i=1;i<=n;++i){
         b[i]=a[i]=read();
     }
     //离散化
     sort(b+1,b+n+1);
     int len=unique(b+1,b+n+1)-b-1;
     for(int i=1;i<=n;++i){
         a[i]=lower_bound(b+1,b+len+1,a[i])-b;
     }
     for(int i=1;i<=len;++i)c[a[i]]=1;     
     for(int i=1;i<=len;++i){
         c[a[i]]=query(a[i]-1);        
         update(a[i]);
     }
}
posted @   Chano_sb  阅读(146)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
点击右上角即可分享
微信分享提示