防线 Defence

这一题写的时候也是懵逼的,想到了大概思路

首先的操作肯定是处理出以 ii 为结尾的最长连续上升序列

那么接下来最朴素的算法可以达到 O(N^2)

有没有更快的做法?

考虑我们枚举的是前 ii 项,那么有些很明显无用的东西被重复枚举了

如果 a[i]>a[j] 并且 g[i]<=g[j] ,那么选 i肯定没有选 j 优,所以考虑用一个

set来维护这个东西,注意细节

#include<bits/stdc++.h>
using namespace std;
set<pair<int,int> > q;
int n,a[200005],h[200005],g[200005];
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
       scanf("%d",&n);g[n+1]=0;
       for(int i=1;i<=n;i++) scanf("%d",&a[i]);
       for(int i=1;i<=n;i++) h[i]=a[i]>a[i-1]?h[i-1]+1:1;//预处理
       for(int i=n;i>=1;i--) g[i]=a[i]<a[i+1]?g[i+1]+1:1;
       q.clear();
       int ans=1;q.insert(make_pair(a[1],h[1]));//用pair维护
       for(int i=2;i<=n;i++){
         pair<int,int> x(a[i],h[i]);
         set<pair<int,int> > :: iterator it=q.lower_bound(x);//找到满足条件的
         if(it!=q.begin()){
            --it;ans=max(ans,(*it).second+g[i]);//更新答案
            if((*it).second>=x.second)continue;//如果已经可以比i更优,直接跳过i
         }
         q.erase(x);q.insert(x);//抹去原本存在的x,重新插入,以便找到位置 
         it=++q.find(x);
         while(it!=q.end()){
          if((*it).second<=x.second&&(*it).first>x.first)q.erase(it);//找到合适的位置插入,并删除不可能的答案 
          else break;
          ++it;//往后迭代 
         }
         q.insert(x);//插入,再次更新 
       }
       printf("%d\n",ans);
    }
}

 

上一篇:【雕爷学编程】MicroPython动手做(01)——春节后入手了K210开发板


下一篇:与众不同