1. 程式人生 > 其它 >溫故而知新——BOM複習

溫故而知新——BOM複習

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]);
     }
}