防线 Defence
Posted coder-cjh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了防线 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);
以上是关于防线 Defence的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ2300[HAOI2011]防线修建 set维护凸包