1471 - Defense Lines

  After the last war devastated your country, you - as the king of the land of Ardenia - decided it was
high time to improve the defense of your capital city. A part of your fortification is a line of mage
towers, starting near the city and continuing to the northern woods. Your advisors determined that the
quality of the defense depended only on one factor: the length of a longest contiguous tower sequence
of increasing heights. (They gave you a lengthy explanation, but the only thing you understood was
that it had something to do with firing energy bolts at enemy forces).
  After some hard negotiations, it appeared that building new towers is out of question. Mages of
Ardenia have agreed to demolish some of their towers, though. You may demolish arbitrary number of
towers, but the mages enforced one condition: these towers have to be consecutive.
  For example, if the heights of towers were, respectively, 5, 3, 4, 9, 2, 8, 6, 7, 1, then by demolishing
towers of heights 9, 2, and 8, the longest increasing sequence of consecutive towers is 3, 4, 6, 7.
Input
  The input contains several test cases. The first line of the input contains a positive integer Z ≤ 25,
denoting the number of test cases. Then Z test cases follow, each conforming to the format described
below.
  The input instance consists of two lines. The first one contains one positive integer n ≤ 2 · 105
denoting the number of towers. The second line contains n positive integers not larger than 109
separated by single spaces being the heights of the towers.
Output
  For each test case, your program has to write an output conforming to the format described below.
You should output one line containing the length of a longest increasing sequence of consecutive
towers, achievable by demolishing some consecutive towers or no tower at all.
Sample Input
2
9
5 3 4 9 2 8 6 7 1
7
1 2 3 10 4 5 6
Output
4
6

解题思路:

  本问题的关键在于set的动态更新,对set集合各种操作的熟练运用是关键。详细思路见紫书。

代码如下:

 1 #include <iostream>
 2 #include <set>
 3 #include <map>
 4 #include <cstdio>
 5 #include <algorithm>
 6 #include <cstring>
 7 using namespace std;
 8 const int maxn=200000+5;
 9 int A[maxn];
10 int f[maxn];
11 int g[maxn];
12 int n;
13 map<int,int> m;
14 set<int> s;
15
16 void pre_procession(){
17     int L=0,R=0;
18     while(L<n){
19         while(R<n&&(R==L||A[R]>A[R-1])){g[R]=R+1-L;R++;}
20         while(L<R){f[L]=R-L;L++;}
21     }
22 }
23 void putset(){
24     int ans=1;
25     for(int i=0;i<n;i++){
26         set<int>::iterator it=s.lower_bound(A[i]);
27         if(it!=s.begin()){
28             it--;
29             ans=max(ans,f[i]+m[*it]);
30             if(m[*it]>=g[i]) continue;
31             it++;
32             if(*it==A[i]&&m[*it]>=g[i]) continue;
33         }
34         s.insert(it, A[i]);
35         m[A[i]]=g[i];
36         int cur=A[i];
37         it=s.upper_bound(cur);
38         while(it!=s.end()&&m[cur]>=m[*it]){
39             cur=*it;
40             s.erase(it);
41             it=s.upper_bound(cur);
42         }
43     }
44     cout<<ans<<endl;
45 }
46 int main(int argc, const char * argv[]) {
47     int T;
48     scanf("%d",&T);
49     while(T--){
50         scanf("%d",&n);
51         for(int i=0;i<n;i++) scanf("%d",&A[i]);
52         pre_procession();
53         m.clear();
54         s.clear();
55         putset();
56     }
57     return 0;
58 }
时间: 2024-10-16 06:08:06

1471 - Defense Lines的相关文章

UVA 1471 - Defense Lines(扫描+二分)

UVA 1471 - Defense Lines 题目链接 题意:给定一个序列,要求删去一个连续子序列后,得到的序列有一个最长的连续递增序列,输出最长连续递增序列长度 思路:先左右扫描一遍,把每个位置往左和往右的最大长度记录下来,然后在从左往右扫描一遍,开一个数组Min用来记录长度i的序列,最后一位的最小值,这个序列是满足单调性的,因为递增序列肯定是1,2,3,4...这样不断往上加的,如果遇到一个a[i]比较小的,就维护Min相应长度下的值,这样在这个单调递增的序列中,每次就可以二分找出最后一

UVA - 1471 Defense Lines 树状数组/二分

                              Defense Lines After the last war devastated your country, you - as the king of the land of Ardenia - decided it washigh time to improve the defense of your capital city. A part of your forti?cation is a line of magetower

uva 1471 Defense Lines

题意: 给一个长度为n(n <= 200000) 的序列,你删除一段连续的子序列,使得剩下的序列拼接起来,有一个最长的连续递增子序列 分析: 就是最长上升子序列的变形.需要加一个类似二分搜索就好. 代码: #include <iostream>#include <cstdio>#include <algorithm>#include <cstring>using namespace std;const int maxn=200005;const int

uva 1471 Defense Lines (降低复杂度)

题意: 给一个长度为n(n <= 200000) 的序列,你删除一段连续的子序列,使得剩下的序列拼接起来,有一个最长的连续递增子序列 思路: 设f[i] 和g[i] 分别表示 以i为开始 和 以i为结束 的最长连续递增序列长度 首先可以想到枚举i和j,然后计算max_len = f[i] + g[i]; 但是这种枚举方法的时间复杂度是O(n^2),这是在加上预处理f[i] 和g[i] 的前提下 所以需要想一个更加优化的方法,避免那么多枚举: 所以想到 只枚举f[i], 通过某种方法快速的找到合适

UVA 1471 Defense Lines 防线

给一个长度为n的序列,要求删除一个连续子序列,使剩下的序列有一个长度最大的连续递增子序列. 最简单的想法是枚举起点j和终点i,然后数一数,分别向前或向后能延伸的最长长度,记为g(i)和f(i).可以先预处理出每一个点能往前和往后延伸的长度(g(i)和f(i)).然后枚举终点j,快速找一个g(j)最大的起点.如果有两个候选的起点,一个j,一个j‘,A[j']<=A[j]且g[j']>g[j],那么j一定可以排除,g(j')更大,而且更容易拼接. 固定i的情况下,所有有价值的(A[j],g(j))

1471 - Defense Lines(二分查找)

这道题非常巧妙,其中的思想很重要.. 题目要求删除一个连续子序列,将剩下的序列拼接起来之后问最长连续递增子序列的长度. 最长子序列的一个常见优化就是用一个数组保存到该点为止的连续子序列长度,但是对于本题来说这样的优化显然还是不够的因为n很大,二重循环还是会超时.所以我们可以只枚举一个量,但是另一个量怎么找呢, 答案是构造一个二元组,a和g,使这两个元素都严格递增.这样我们在枚举一个i时只要二分找到第一个比a[i]小的值,他对应的那个g也是最大的. 然后问题的关键就在与对集合的操作,说白了就是构造

UVa 1471 Defense Lines 算法分析

难度:β+ 用时:0 min 题目:?? 代码:?? 这是一道贪心题. 然而不是一道简单的贪心题. 题目要求在一个大区间里删掉一个区间使得与该区间左右相邻的连续递增序列之和最长. 注意左右两侧的连续递增序列是合并后当作一整个看的. (解释不清还是看书吧) 这题可以用暴力,然而会 TLE. 暴力做法就是统计以 i 点结尾的最长序列长度 g(i) 和以 i 点开头的最长序列长度 f(i)(递增的). 然后枚举 i,j,答案是 max { g(i) + f(j) }.这样会超时. 正解算法是在这基础上

UVA - 1471 Defense Lines (set/bit/lis)

紫薯例题+1. 题意:给你一个长度为n(n<=200000)的序列a[n],求删除一个连续子序列后的可能的最长连续上升子序列的长度. 首先对序列进行分段,每一段连续的子序列的元素递增,设L[i]为下标i对应的元素向左能延伸到的最大长度(在同一段内),R[i]为向右能延伸到的最大长度,则问题转化成了对于每个下标i,找到在它前面的下标j中a[j]<a[i]且L[j]最大的j,然后用R[i]+L[j]去更新ans. 第一种方法是用一个二元组(x,y)表示大小为x的元素所对应的L的值,用一个set保存

【二分】Defense Lines

[UVa1471] Defense Lines 算法入门经典第8章8-8 (P242) 题目大意:将一个序列删去一个连续子序列,问最长的严格上升子序列 (N<=200000) 试题分析:算法1:直接暴力,对于一个删除序列,枚举头和尾,然后看最长上升子序列.时间复杂度:O(N^3) 算法2:L[i]表示以i为结尾的最长严格上升子序列长度,R[i]表示以i为开头的最长严格上升子序列长度. 预处理:O(N)  然后依旧是枚举头和尾,那么答案就是L[i]+R[j]了.时间复杂度:O(N^2) 算法3:第