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))按照A[j]排序(A[j]相同的值保留g(j)大的那个),将会形成一个有序表,根据之前的结论g(j)是递增的,有序,那么二分查找就派上用处了。

然后再考虑,变动i对之前的有序表的影响,i增加,把之前的A[i],g(i)加入到有序表中,如果满足A[i‘]比它A[i]小且g(i‘)最大的二元组,即它前面的一个元素,满足g(i‘)>=g(i),那么这个元素不该保留。否则应该加入这个二元组,加入这个二元组之后,为了保持有序表的性质,还要往后检查删除一些g(i*)小的元素。

终于想得比较透彻了,实现方式是set,用pair来保证二元组,pair比较的时候是先比较第一维,相等时才比较第二维。至于第二种实现,用数组保存g(j)对应最小的A[j]值,复习LIS时再补上吧~

#include<bits/stdc++.h>
#define MP make_pair
#define se second
#define fi first
using namespace std;
const int maxn = 2e5+5;
typedef pair<int,int> pii;
int A[maxn];
int g[maxn];//<-
int f[maxn];//->
set<pii> s;

int main()
{
    int T; scanf("%d",&T);
    while(T--){
        int n; scanf("%d",&n);
        for(int i = 0; i < n; i++) scanf("%d",A+i);
        if(n == 1) { printf("1\n"); continue; }
        g[0] = 1;
        for(int i = 1; i < n; i++) {
            if(A[i]>A[i-1]) g[i] = g[i-1]+1;
            else g[i] = 1;
        }
        f[n-1] = 1;
        for(int i = n-2; i >= 0; i--) {
            if(A[i]<A[i+1]) f[i] = f[i+1]+1;
            else f[i] = 1;
        }
        s.clear(); s.insert(MP(A[0],g[0]));
        int ans = 1;
        for(int i = 1; i < n; i++){
            pii cur(A[i],g[i]);
            set<pii>::iterator it = s.lower_bound(cur);
            bool keep = true;
            if(it!=s.begin()){
                it--;
                ans = max(ans,it->se+f[i]);
                keep = it->se < cur.se;
            }
            if(keep){
                s.erase(cur); s.insert(cur);
                it++; it++;
                while(it != s.end() && it->se <= cur.se ) s.erase(it++);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
时间: 2024-10-15 05:03:58

UVA 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 算法分析

难度:β+ 用时: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保存

uva 1471 defence lines——yhx

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 fortication is a line of magetowers, starting near the city and continuing to t

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

1471 - Defense Lines(二分查找)

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