51nod 1218 最长递增子序列 V2 【最长递增+复杂判断】

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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值