码迷,mamicode.com
首页 > 其他好文 > 详细

[51Nod 1218] 最长递增子序列 V2 (LIS)

时间:2018-09-13 22:34:35      阅读:230      评论:0      收藏:0      [点我收藏+]

标签:html   putchar   names   ==   传送门   哪些   git   ref   efi   

传送门

Description

数组A包含N个整数。设S为A的子序列且S中的元素是递增的,则S为A的递增子序列。如果S的长度是所有递增子序列中最长的,则称S为A的最长递增子序列(LIS)。A的LIS可能有很多个。例如A为:1 3 2 0 4,1 3 4,1 2 4均为A的LIS。其中元素1和4一定会出现在LIS当中,元素2和3可能会出现在LIS当中,元素0一定不会出现在LIS当中。给出数组A,输出哪些数可能出现在LIS中,哪些数一定出现在LIS中。输出数字对应的下标,下标编号从1开始,编号为1 - N。例如:1 3 2 0 4,可能出现的元素为3和2,对应的下标为2和3。一定出现的元素为1和4,对应下标为1和5.

Input

第1行:1个数N,表示数组的长度。(1 <= N <= 50000)
第2 - N + 1行:每行1个数A[i],表示数组的元素(0 <= A[i] <= 10^9)

Output

第1行:可能出现在LIS中的数的下标,中间用空格分隔。(输出的下标按照递增排序)
第2行:一定会出现在LIS中的数的下标,中间用空格分隔。(输出的下标按照递增排序)

Sample Input

5
1
3
2
0
4

Sample Output

A:2 3
B:1 5

Solution

正的跑最长上升子序列,反的跑最长下降子序列
如果正反的dp值相加等于len+1(自己加了两次)说明可能在LIS中
若dp值独一无二且可能出现即为一定出现

Code

//By Menteur_Hxy
#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define F(i,a,b) for(register int i=(a);i<=(b);i++)
#define R(i,a,b) for(register int i=(b);i>=(a);i--)
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin)),p1==p2?EOF:*p1++)
using namespace std;

char buf[1<<21],*p1,*p2;
inline int read() {
    int x=0,f=1; char c=getchar();
    while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}
    while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();
    return x*f;
}

const int N=50010;
int n,len;
bool vis1[N],vis2[N];
int a[N],s[N],f[N],g[N];
vector<int> V[N];

int main() {
    n=read();
    F(i,1,n) a[i]=read();
    F(i,1,n) {
        if(s[len]<a[i]) s[++len]=a[i],f[i]=len;
        else {
            int tmp=lower_bound(s+1,s+1+len,a[i])-s;
            s[tmp]=a[i];f[i]=tmp;
        }
    }
    len=0;
    R(i,1,n) {
        if(s[len]<-a[i]||!len) s[++len]=-a[i],g[i]=len;//无脑取负qwq
        else {
            int tmp=lower_bound(s+1,s+1+len,-a[i])-s;
            s[tmp]=-a[i];g[i]=tmp;
        }
    }
    F(i,1,n) {
        if(f[i]+g[i]==len+1) vis1[i]=1;
        if(vis1[i]) V[f[i]].push_back(i);
    }
    F(i,1,n) {
        int siz=V[i].size();
        if(siz==1) vis2[V[i][0]]=1;
    }
    // F(i,1,n) cout<<f[i]<<" ";cout<<endl;
    // F(i,1,n) cout<<g[i]<<" ";cout<<endl;
    putchar('A');putchar(':'); F(i,1,n) if(vis1[i]&&!vis2[i]) printf("%d ",i);
    putchar('\n');
    putchar('B');putchar(':'); F(i,1,n) if(vis2[i]) printf("%d ",i);
    return 0;
}

[51Nod 1218] 最长递增子序列 V2 (LIS)

标签:html   putchar   names   ==   传送门   哪些   git   ref   efi   

原文地址:https://www.cnblogs.com/Menteur-Hxy/p/9643281.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!