Uva 1471 Defense Lines(LIS变形)
题意:
给你一个数组,让你删除一个连续的子序列,使得剩下的序列中有最长上升子序列, 求出这个长度。
题解:
预处理:先求一个last[i],以a[i]为开始的合法最长上升子序列的长度。再求一个pre[i],以a[i]为结尾的合法最长上升子序列长度。
那么这题的答案就是:max(pre[j]) + last[i]。(j<=a[i] - 1)。
例如a[i]为3的话, 答案就是max(以1结尾的LIS长度, 以2结尾的LIS长度) + 以3开始LIS长度。
dis[i] 是 LIS 长度为i的时候,最小的a[i]。(详细请看LIS nlogn算法)
所以
len = (lower_bound(dis+1, dis+1+i, a[i]) - (dis+1)) + last[i]。//二分查找
ans = max (ans, len);
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <string> 6 #include <vector> 7 #include <map> 8 #include <set> 9 #include <queue> 10 #include <sstream> 11 #include <algorithm> 12 using namespace std; 13 #define pb push_back 14 #define mp make_pair 15 #define ms(a, b) memset((a), (b), sizeof(a)) 16 //#define LOCAL 17 #define eps 0.0000001 18 typedef long long LL; 19 const int inf = 0x3f3f3f3f; 20 const LL INF = 0x7fffffff; 21 const int maxn = 200000+10; 22 const int mod = 1000000007; 23 int a[maxn]; 24 int last[maxn]; 25 int pre[maxn]; 26 int dis[maxn]; 27 void solve() 28 { 29 int n; 30 scanf("%d", &n); 31 for(int i=1;i<=n;i++) scanf("%d", &a[i]); 32 ms(pre, 0); 33 ms(last, 0); 34 last[n] = 1; 35 for(int i=n-1;i>0;i--){ 36 if(a[i] < a[i+1]){ 37 last[i] = last[i+1] + 1; 38 }else last[i] = 1; 39 } 40 pre[1] = 1; 41 for(int i= 2;i<=n;i++){ 42 if(a[i] > a[i-1]){ 43 pre[i] = pre[i-1] + 1; 44 }else pre[i] = 1; 45 } 46 for(int i=0;i<=n;i++) dis[i] = inf; 47 int ans = 0; 48 for(int i=1;i<=n;i++){ 49 int len = (lower_bound(dis+1, dis+1+i, a[i]) -(dis+1))+ last[i]; 50 ans = max(ans, len); 51 dis[pre[i]] = min(a[i], dis[pre[i]]); 52 } 53 printf("%d\n", ans); 54 } 55 int main() { 56 #ifdef LOCAL 57 freopen("jumping.in", "r", stdin); 58 // freopen("output.txt", "w", stdout); 59 #endif // LOCAL 60 int t; 61 scanf("%d", &t); 62 while(t--){ 63 solve(); 64 } 65 return 0; 66 }