P1020 导弹拦截(最长不上升子序列and最长上升子序列长度的nlogn做法)

题目链接:https://www.luogu.org/problem/P1020

 

题目大意:求最长不上升子序列长度 and 最长上升子序列长度

 

题目思路:使用lower_bound和upper_bound,以最长上升子序列举例,如果新来的元素大于目前维护的序列的最后一个元素,那就加进来,如果比他小,那么就用lower_bound获得第一个大于它的数字的位置,并代替它,之所以要用lower_bound是因为不能出现重复元素,这样就能保证想要得到的序列一定能尽可能长,但是要注意,最后得到的序列中的元素并不是真正的最长上升子序列,这种做法只能保证其长度保持正确。

相反地,对于最长不上升子序列,需要找到的第一个小于它的位置,并换掉它,这里要用upper_bound,因为可以出现重复元素,如果把比小的变大能多多益善

 

以下是代码:

#include
using namespace std;
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(ll i=a;i<=b;i++)
#define per(i,a,b) for(ll i=a;i>=b;i--)
#define ll long long
const int MAXN = 1e5+5;
const ll MOD =1e9+7;
int a[MAXN];
int dp1[MAXN],dp2[MAXN];
int main(){
    int n=0;
    while(~scanf("%d",&a[++n]));
    n--;
    int len1=1,len2=1;
    dp1[1]=dp2[1]=a[1];
    rep(i,2,n){
        if(a[i]<=dp1[len1])dp1[++len1]=a[i];
        else{
            int pos=upper_bound(dp1+1,dp1+len1+1,a[i],greater())-dp1;
            dp1[pos]=a[i];
        }
        if(a[i]>dp2[len2])dp2[++len2]=a[i];
        else{
            int pos=lower_bound(dp2+1,dp2+len2+1,a[i])-dp2;
            dp2[pos]=a[i];
        }
    }
    cout<

 

你可能感兴趣的:(贪心,思维)