參考https://www.cnblogs.com/yuelian/p/8745807.htmlhtml
注意最長上升子序列用lower_bound,最長不降低子序列用upper_bound
好比123458, 加入了5
假設求最長上升子序列
這個時候只能替換5,不能替換8(嚴格上升)
雖然沒有用,可是這樣不會錯,寫upper_bound就錯了。
假設求最長不降低子序列
這樣應該替換8,替換5並非最優的
因此用upper_bound數組
最長上升子序列(LIS)nlogn模板spa
#include<cstdio> #include<algorithm> #define REP(i, a, b) for(int i = (a); i < (b); i++) using namespace std; const int MAXN = 51234; int a[MAXN], f[MAXN], n; //a數組從0開始,f數組從1開始 int main() { scanf("%d", &n); REP(i, 0, n) scanf("%d", &a[i]); int len = 1; f[1] = a[0]; //初始化 REP(i, 1, n) { if(a[i] > f[len]) f[++len] = a[i]; //這裏是++len 如果不降低就改成>= else f[lower_bound(f + 1, f + len + 1, a[i]) - f] = a[i]; //注意f數組是從1開始 } printf("%d\n", len); return 0; }
最長不降低子序列(LIS)nlogn模板.net
#include<cstdio> #include<algorithm> #define REP(i, a, b) for(int i = (a); i < (b); i++) using namespace std; const int MAXN = 51234; int a[MAXN], f[MAXN], n; int main() { scanf("%d", &n); REP(i, 0, n) scanf("%d", &a[i]); int len = 1; f[1] = a[0]; REP(i, 1, n) { if(a[i] >= f[len]) f[++len] = a[i]; //>改爲>= else f[upper_bound(f + 1, f + len + 1, a[i]) - f] = a[i]; //lower_bound改爲upper_bound } printf("%d\n", len); return 0; }
若是要求最長降低子序列或者最長不上升子序列符號改變,同時二分加上cmp便可code
另外有個神奇的定理
若是是求一個數組最少分紅幾組最長不上升子序列的話
答案就是最長上升子序列(上升改爲降低也成立)
導彈攔截那題要用到htm
輸出路徑的版本,見https://blog.csdn.net/lxcxingc/article/details/81238008blog
#include<cstdio> #include<algorithm> #define REP(i, a, b) for(int i = (a); i < (b); i++) using namespace std; const int MAXN = 51234; int a[MAXN], f[MAXN]; int ans[MAXN], pos[MAXN], n; int main() { scanf("%d", &n); REP(i, 0, n) scanf("%d", &a[i]); int len = 1; f[1] = pos[1] = a[0]; REP(i, 1, n) { if(a[i] > f[len]) f[++len] = a[i], pos[i] = len; else f[pos[i] = lower_bound(f + 1, f + len + 1, a[i]) - f] = a[i]; } printf("%d\n", len); int maxx = 1e9, t = len; for(int i = n - 1; i >= 0; i--) { if(t == 0) break; if(pos[i] == t && maxx > a[i]) { maxx = a[i]; ans[t--] = a[i]; } } REP(i, 1, len + 1) printf("%d ", ans[i]); puts(""); return 0; }