UVa1471 - Defense Lines

UVa1471 - 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 Z25 , 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 n2105 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

题意

给出一个序列,问去掉一个区间后得到的最长上升子串的长度最长是多少。

题解

最简单的想法就是枚举去掉的区间 [i,j] ,之后向左右方向寻找最长上升子序列的长度。枚举的复杂度 O(n2) ,加上寻找的复杂度一共 O(n3) ,TLE。加上一个预处理后可以优化到 O(n2) g[i] f[i] i 为尾部和头部的连续子串的长度。此时算法是O(n2)的,仍然不够优越。我们可以维护一个二元组的set,二元组中存 A[i] g[i] ,并按照 A[i] 排序。如果 i 之前有一个位置j A[j]A[i] g[j]g[i] ,那么 i 对应的二元组不会比j对应的二元组更优,所以枚举 i 之后将要向前寻找是否保留i对应的二元组,再向后比较是否删除后面的二元组。总复杂度大概为 O(nlogn)

代码

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
#include <set>
#define fout freopen("out.txt","w",stdout)
#define fin freopen("in.txt","r",stdin)

using namespace std;

const int MAX=200005;
struct node
{
    int A;
    int g;
    node(int A=0,int g=0):A(A),g(g){}
    bool operator<(const node &R)const
    {
        return A<R.A;
    }
};
int A[MAX],g[MAX],f[MAX];
int T,n;
set<node> S;
node pre;
bool mark;
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d",&A[i]);
        if(n==1)
        {
            printf("1\n");
            continue;
        }
        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;
        }
        g[0]=1;
        S.clear();
        S.insert(node(A[0],g[0]));
        int ans=1;
        for(int i=1;i<n;i++)
        {
            if(A[i]>A[i-1])
                g[i]=g[i-1]+1;
            else
                g[i]=1;
            node temp(A[i],g[i]);
            set<node>::iterator it=S.lower_bound(temp);
            mark=true;
            if(it!=S.begin())
            {
                pre=*(--it);
                it++;
                ans=max(ans,pre.g+f[i]);
                mark=pre.g<g[i];
            }
            if(mark)
            {
                S.erase(temp);
                S.insert(temp);
                it=S.lower_bound(temp);
                it++;
                while(it!=S.end()&&temp.g>=it->g)
                    S.erase(it++);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值