1218 最长递增子序列 V2 【最长递增+复杂判断】
基准时间限制:1 秒 空间限制:131072 KB 分值: 160
难度:6级算法题
数组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中的数的下标,中间用空格分隔。(输出的下标按照递增排序)
Input示例
5 1 3 2 0 4
Output示例
A:2 3 B:1 5
变量比较多 不过代码很短 不难理解
#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int s[50005],dex[50005],maxn[50005],cnt[50005],m[50005],vis[50005];
int n,len=1; //s保存输入数据 dex保存最长递增子序列 maxn保存当前数是第几大
int main() //cnt表示第x大的数出现的次数 vis表示这个数被使用过 m表示从后遍历第k大的数的最大值
{
cin>>n;
cin>>s[0];
dex[0]=s[0];
maxn[0]=1;
for(int i=1;i<n;i++){
cin>>s[i];
int k=lower_bound(dex,dex+len,s[i])-dex;
maxn[i]=k+1;
if(k==len){
dex[len++]=s[i];
}else{
dex[k]=s[i];
}
}
m[len+1]=1<<30;
for(int i=n-1;i>=0;i--){
if(m[maxn[i]+1]>s[i]){
vis[i]=maxn[i];
cnt[maxn[i]]++;
m[maxn[i]]=max(m[maxn[i]],s[i]);
}
}
cout<<"A:";
for(int i=0;i<n;i++){
if(vis[i] && cnt[vis[i]]>1)
printf("%d ",i+1);
}
cout<<endl<<"B:";
for(int i=0;i<n;i++){
if(vis[i] && cnt[vis[i]]==1)
printf("%d ",i+1);
}
return 0;
}