习题:宇宙飞船(LIS&思维)

题目

思路

移动飞船的操作很显然可以转换成为删掉的操作,如果删掉的点为\(i\),就是将\(p_{i-1}\)\(p_i\)

相连

这些绳子都是有限制性的,

定义一个概念“阶段”表示某一段单调的位置

可以发现,最终的答案一定是一些阶段的组合

同时要满足一个阶段中的位置一定在上一个阶段最后两个位置所规定的范围之内

以pos为x轴,以id为y轴,一个合法的方案即为

其中黑色的线表示飞船之间点的相连

仔细观察一个方案,发现其一定是类似于一个单峰,如图中红色的线一样

也就是说如果有一个单峰,一定可以反过来构造出一种方案

即对于每一个点求出以这个点结尾的最长上升子序列和最长下降子序列,这两个的长度相加求一个最大值,注意这里x会被算两次,需要减去1

代码

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
using namespace std;
int n;
int a[200005];
vector<int> s;
int dp[200005];
int ans=-1;
int main()
{
    //freopen("spaceship.in","r",stdin);
    //freopen("spaceship.out","w",stdout);
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    //cout<<'\n';
    for(int i=1;i<=n;i++)
    {
        int t=lower_bound(s.begin(),s.end(),a[i])-s.begin();
        if(t==s.size())
            s.push_back(a[i]);
        else   
            s[t]=a[i];
        dp[i]=t+1;
        /*for(int i=0;i<s.size();i++)
            cout<<s[i]<<' ';
        cout<<'\n';*/
    }
    /*for(int i=1;i<=n;i++)
        cout<<dp[i]<<' ';
    cout<<'\n';*/
    s.clear();
    for(int i=1;i<=n;i++)
        a[i]=-a[i];
    for(int i=1;i<=n;i++)
    {
        int t=lower_bound(s.begin(),s.end(),a[i])-s.begin();
        if(t==s.size())
            s.push_back(a[i]);
        else
            s[t]=a[i];
        ans=max(ans,t+dp[i]);
    }
    cout<<ans;
    return 0;
}
posted @ 2020-10-31 17:10  loney_s  阅读(147)  评论(0)    收藏  举报