解題關鍵:
如果將子串行按照長度由短到長排列,將他們的最大元素放在一起,形成新序列$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 #include6using
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 #include6using
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 #include6using
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 的最長公共子串行即可。顯然這裡最長公共子串行...