如何判断某个位置是不是LIS或者反LIS的数?

如何判断某个位置是不是LIS或者反LIS的数?
笔者是在前几天的abc354这一场的f题发现的,最长上升子序列很显然,我们在求的过程中,设 \(dp[i]\) 为以i位置结尾的最长上升序列的长度,然后求一边所有的最长长度即可,那么对于这种定义,我们考虑一个反定义,即:\(dp2[j]\) 为以j位置开头的最长上升序列的长度,那么显然有这样一个定义:若我们已知最长上升子序列长度,那么我们一定会有 \(dp[i]+dp[2]-1=max(dp[j])\) 这里的 \(dp[j]\) 就是最长上升子序列的长度,这个定义是显然的,所以我们求两次 \(Lis\) 即可
对于以 \(i\) 结尾的,正常求即可,对于以 \(i\) 开头的,我们直接倒着求一边最长下降子序列即可,由于数据范围较大,不可直接用动归,这里笔者选择了二分贪心的思路去做,其他的做法还有线段树和树状数组均可,笔者在后面会补

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10,mod=1e9+7;
void solve(){
    int n; cin>>n;
    vector<int>q(n+1),a(n+1);
    for(int i=1;i<=n;i++) cin>>a[i];
    q[0]=-2e9;
    int num=0;
    vector<int>lis(n+1);
    for(int i=1;i<=n;i++){
        if(a[i]>q[num]) q[++num]=a[i],lis[i]=num;
        else{
            int l=1,r=num;
            while(l<r){
                int mid=l+r>>1;
                if(a[i]<=q[mid]) r=mid;
                else l=mid+1;
            }
            q[r]=a[i],lis[i]=r;
        }        
    }
    reverse(a.begin()+1,a.end());
    vector<int>_lis(n+1);
    q[0]=2e9,num=0;
    for(int i=1;i<=n;i++){
        if(a[i]<q[num]) q[++num]=a[i],_lis[n-i+1]=num;
        else{
            int l=1,r=num;
            while(l<r){
                int mid=l+r>>1;
                if(a[i]>=q[mid]) r=mid;
                else l=mid+1;
            }
            q[l]=a[i],_lis[n-i+1]=l;
        }
    }   
    vector<int>res;
    for(int i=1;i<=n;i++){
        if(lis[i]+_lis[i]-1==num) 
            res.push_back(i);
    }
    cout<<res.size()<<'\n';
    for(auto x:res) cout<<x<<' ';
    cout<<'\n';
}
signed main(){
    std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);int t;cin>>t;while(t--)solve();
}
posted @ 2024-05-20 08:29  o-Sakurajimamai-o  阅读(14)  评论(0编辑  收藏  举报
-- --