HDU 5489 Removed Interval (LIS变形)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5489
给你n个数,要删去其中连续的L个,问你删去之后的LIS最大是多少?
我们先预处理出以i下标为开头的LIS,存到数组中。
然后可以枚举长为L的区间,每次移动,左边增加一个,右边删除一个。
最长上升子序列长度 = 窗口右边以右边第一个元素开头的最长上升子序列 + 窗口左边最大元素小于窗口右边第一个元素的最长上升子序列。
比如 1 2 [4 3] 2 3 5 , LIS = 3 + 1 = 4
求以i开头的LIS 只要倒着求最长下降子序列 or 倒着a[i]变负求最长上升子序列即可。
代码写的有点乱。
1 //#pragma comment(linker, "/STACK:102400000, 102400000") 2 #include <algorithm> 3 #include <iostream> 4 #include <cstdlib> 5 #include <cstring> 6 #include <cstdio> 7 #include <vector> 8 #include <cmath> 9 #include <ctime> 10 #include <list> 11 #include <set> 12 #include <map> 13 using namespace std; 14 typedef long long LL; 15 typedef pair <int, int> P; 16 const int N = 1e5 + 5; 17 int dp1[N], dp2[N], a[N], inf = 1e9 + 7; 18 int y[N], x[N]; // y[i]表示以i下标为开头的LIS,x[i]表示以i为结尾的LIS 19 20 int main() 21 { 22 int t, n, m; 23 scanf("%d", &t); 24 for(int ca = 1; ca <= t; ++ca) { 25 scanf("%d %d", &n, &m); 26 for(int i = 1; i <= n; ++i) { 27 scanf("%d", a + i); 28 dp1[i] = dp2[i] = inf; 29 } 30 dp2[0] = dp1[0] = inf; 31 int ans = 0; 32 for(int i = n; i >= 1; --i) { //倒着求变负,求以i开头的LIS 33 int pos = lower_bound(dp2, dp2 + n, -a[i]) - dp2; 34 y[i] = pos + 1; 35 //cout << y[i] << endl; 36 dp2[pos] = -a[i]; 37 if(i == m + 1) { 38 ans = lower_bound(dp2, dp2 + n, inf) - dp2; 39 } 40 } 41 //cout << ans << endl; 42 for(int i = 1; i <= n; ++i) { 43 int pos = lower_bound(dp1, dp1 + n, a[i]) - dp1; 44 x[i] = pos + 1; 45 dp1[pos] = a[i]; 46 if(i == n - m) { 47 ans = max(int(lower_bound(dp1, dp1 + n, inf) - dp1), ans); 48 break; 49 } 50 } 51 //cout << ans << endl; 52 printf("Case #%d: ", ca); 53 dp1[0] = inf; 54 for(int i = 1; i <= n; ++i) { 55 dp1[i] = inf; 56 } 57 for(int i = m + 1; i <= n; ++i) { 58 int pos = lower_bound(dp1, dp1 + n, a[i] - 1) - dp1; //求滑窗左边刚好小于滑窗右边第一个数的LIS 59 ans = max(ans, y[i] + (a[i] - 1 == a[pos] ? pos + 1 : pos)); 60 *lower_bound(dp1, dp1 + n, a[i - m]) = a[i - m]; 61 } 62 printf("%d\n", ans); 63 } 64 return 0; 65 }