UVA 1471 Defense Lines 单调队列优化

题意:给出长度为N的序列,现在让你删除一个连续的、任意长度的序列,从而形成一个最长的上升子序列。

思路:第一遍看错题了,以为是标准的最长上升子序列,然后就错了。

          再看一遍题意,其实只是让你删除一个连续的、任意长度的序列,注意只有一次机会。

          这样,我们就能发现,其实最终的最长上升子序列是由两段拼成的,这两段分别是连续的。

          首先第一个技巧,就是分别求出以位置i开始和结束的最长上升子序列f(i),g(i)。这个可以O(N)得到。

          但是我们要是直接暴力枚举i,j, i < j 的话,复杂度为O(N^2),会超时。这样,我们就枚举i,同时去找最优的j,使f(i) + g(j)最大。

          我们可以发现,同标准的最长上升子序列一样,对于f(i) = f(j),且A[i] < A[j],位置i比位置j更有可能成为最优解。这就是说,对于相同的长度,数字的值更小,更能继续延长该序列。这样,我们就能像标准的最长上升子序列一样,用单调队列进行优化。对于每个f(i),保存最小的A[i]。因为是单调的,我们就能二分找目标值。

         所以整体的复杂度为:O(nlogn)

代码如下:

#include <cstdio>
#include <algorithm>
#include <set>
#include <cstring>

using namespace std;

const int MAX = 200010;

int N,T,a[MAX],f[MAX],g[MAX],b[MAX];

int main(void)
{
    //freopen("input.txt","r",stdin);
    scanf("%d",&T);
    while(T--){
        scanf("%d",&N);
        for(int i = 0; i < N; ++i)
            scanf("%d",a+i);
        for(int i = 0; i < N; ++i)
            if(i && a[i] > a[i-1])
                f[i] = f[i-1] + 1;
            else
                f[i] = 1;
        for(int i = N - 1; i >= 0; --i)
            if(i + 1 < N && a[i] < a[i+1])
                g[i] = g[i+1] + 1;
            else
                g[i] = 1;
        int ans = 0;
        memset(b,0x3f,sizeof(b));
        b[0] = 0;
        for(int i = 0; i < N; ++i){
            ans = max(ans,g[i] + (int)(lower_bound(b,b+N+1,a[i]) - b - 1));
            b[f[i]] = min(b[f[i]],a[i]);
        }
        printf("%d\n",ans);
    }
    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值