dp 最長單調遞增子串行LIS

2022-05-01 23:36:19 字數 3081 閱讀 8680

解題關鍵:

如果將子串行按照長度由短到長排列,將他們的最大元素放在一起,形成新序列$b\left\,, \ldots  \ldots ,} \right\}$,則序列$b$滿足$ < <  \ldots  \ldots  < $。這個關係比較容易說明,假設$}$表示序列a中長度為$x$的遞增序列中的第$y$個元素,顯然,如果在序列$b$中存在元素$} > }$,且$m < n$則說明子串行$$的最大元素小於$$的最大元素,因為序列是嚴格遞增的,所以在遞增序列$$中存在元素$} < }$,且從$}$到$}$形成了乙個新的長度為$m$的遞增序列,因為$} > }$,所以$} > }$,這就說明在序列$b$中還存在乙個長度為$m$,最大元素為$} < }$的遞增子串行,這與序列的定義,$}$是所有長度為m的遞增序列中第$m$個元素最小的序列不符,所以序列$b$中的各元素嚴格遞增。

注意liss存的是下標,主要是為了求pre用,若只求max,你當然可以設成值。 

**了,剛發現《挑戰競賽程式設計》上有乙個**非常非常簡短的模板,炸了;

stl模板:

1 #include2 #include3 #include4 #include5 #include6

using

namespace

std; 78

const

int n=131072

; 9

int n=7, a[n] = ;

10 template

11int

lis (cmp cmp)

17return

m;18

} 19

bool greater1(int

value)

2223

intmain()

最終模板:

1 #include2

#define inf 0x3f3f3f3f

3using

namespace

std;

4 typedef long

long

ll;5 ll a[50002],dp[50002];6

intmain()

12 fill(dp,dp+n,inf);

13for(ll i=0;i)

16 printf("

%lld\n

",lower_bound(dp,dp+n,inf)-dp);

17 }

自己改進模板(不帶路徑):注意二分時上界為len+1就ok了,也可以fill成inf,更簡單明瞭

1 #include2

#define inf 0x3f3f3f3f

3using

namespace

std;

4 typedef long

long

ll;5

int arr[50002],dp[50002];6

intn,len;

7int find1(int

x)14

return

r;15}16

intlis()

23return

len;24}

25int

main()

30 ll ans=lis();

31 printf("

%lld\n

",ans);

32return0;

33 }

帶路徑模板1

1 #include2 #include3 #include4 #include5 #include6

using

namespace

std;

7 typedef long

long

ll;8

int a[50002],dp[50002],pre[50002],res[50002

],n;

9int

len;

1011

int find1(int

x)18

return

r;19}20

21int

lis()

2930

int k=dp[len],t=len;

31while(pre[k]!=k)

35 res[t]=a[k];

36return

len;37}

38int

main()

48 printf("\n"

);49 }

帶路徑模板2

1 #include2 #include3 #include4 #include5 #include6

using

namespace

std;

7 typedef long

long

ll;8

int arr[50002],liss[50002],pre[50002],res[50002];9

int find1(int i,int l,int

r)16

return

r;17}18

int lis(int

len)//

增加這條語句主要是pre的影響,不需要路徑的話,完全可以去掉。

27if(index==max-1&&arr[liss[index]]32 liss[index]=i;

33 pre[i]=liss[index-1

];34}35

36int k=liss[max-1],t=max-1;37

while(pre[k]!=k)

41 res[t]=arr[k];

42return

max;43}

44int

main()

50for(int i=0;i)

53 ll ans=lis(n);

54 printf("

%lld\n

",ans);

55for(int i=0;i)

58 printf("\n"

);59 }

dp 最長遞增子串行 (LIS)

首先引出乙個例子 問題 給你乙個長度為 6 的陣列 陣列元素為 則其最長單調遞增子串行為 並且長度為 5 分析 題目所要找的遞增子串行 想想有什麼特點呢 是不是會發現 所有的遞增序列 前乙個數一定小於後乙個數 並且如果給所有從小到大的數標號 會得到一串遞增的數 既然是借助動態規劃分析問題 那麼當前的...

最長遞增子串行 LIS

對於這個問題,最直觀的dp方法是cnt i 表示以height i 結束的最長遞增子串行的元素的個數,遞迴方程是cnt i max for max i 0 i求出整個數列的最長遞增子串行的長度 if b i max max b i cout return 0 顯然,這種方法的時間複雜度仍為o n 2...

最長遞增子串行 LIS

給定乙個長度為n的陣列,找出乙個最長的單調自增子序列 不一定連續,但是順序不能亂 例如 給定乙個長度為6的陣列a,則其最長的單調遞增子串行為,長度為4.這個問題可以轉換為最長公共子串行問題。如例子中的陣列a,則我們排序該陣列得到陣列a 然後找出陣列a和a 的最長公共子串行即可。顯然這裡最長公共子串行...