[51Nod 1218] 最长递增子序列 V2 (LIS)
Posted menteur-hxy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[51Nod 1218] 最长递增子序列 V2 (LIS)相关的知识,希望对你有一定的参考价值。
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('
');
putchar('B');putchar(':'); F(i,1,n) if(vis2[i]) printf("%d ",i);
return 0;
}
以上是关于[51Nod 1218] 最长递增子序列 V2 (LIS)的主要内容,如果未能解决你的问题,请参考以下文章