不做题不知道自己是fw之最长不下降子序列

同桌的你 25’
描述
在家上了一个多月的网课,JM同学迎来了人生第一次网课月考。

由于网课的缘故,JM同学总是在上课的时候,偷偷的写代码,努力变强。So,月考成绩可想而知~

那叫一个惨不忍睹啊~ 把班主任,各科老师给气的… 一点办法没有~~ 嗐~~

等到开学了,班主任为了不让JM以及班上其他成绩不好的同学落下,决定借鉴“一带一路”政策,在班级也来一个“一带一路,相互扶持”的政策。

调坐班级同学座位,让成绩靠前的同学和成绩靠后的同学坐一起,一个帮助一个。

班级里的人数刚好可以拼坐成N对同桌(2人同桌),即总共有2N张课桌,

由于教室形状特殊,所有同学的课桌摆成一排,编号1,2,3,…,2N,编号1,2为第一桌,编号3,4为第二桌…依次类推。

wlxsq老师决定让月考成绩第1名的和第2n名的同学坐第一桌,第2名的和第2n-1名的同学第2桌,…,第i名的名和第2n−i+1名的坐第i桌,依次类推。

现在wlxsq按照座位从左往右依次给你班上2N名同学的成绩,由于教室比较窄,一次只能一个同学搬课桌出列插入到其他位置。

wlxsq老师现在想知道,最少需要几个同学搬课桌出列调整才能够让所有同学和自己对应的同学坐同桌呢?请你来帮帮wlxsq吧~

注意:第一名和最后一名只要是同桌即可,谁坐左边谁坐右边都可以,以此类推。

输入
第一行输入一个整数N,表示有N对同桌。

第二行输入2N个整数,表示从左到右每一张桌子上同学的成绩ai。

输出
输出一个整数表示最少需要几个同学出列调整。

样例
输入复制
3
16 2 1 7 5 10
输出复制
2
提示
样例1解释

第1至第6张课桌上坐着的同学成绩为16,2,1,7,5,10,对应的排名:1,5,6,3,4,2。

第一步:让成绩为1的同学搬桌子出列插入到第1,2张桌子(成绩为16和22)中间,从左往右6张桌子上坐着的同学成绩依次为:16,1,2,7,5,10

第二步:让成绩为10的同学搬桌子出列插入到第3,4桌子(成绩为2和7)中间,从左往右6张桌子上坐着的同学成绩依次为:16,1,2,10,7,5。

所以只需要2次操作,使得(16,1)坐第一桌,(2,10)坐第二桌,(7,5)坐第三桌。

数据规模:

对于100%的数据,n<=1e5,1≤ai<=1e9,数据保证不存在成绩相同的两个同学

**思路:最长不下降子序列模版。本人用c语言写的,所以用到了结构体储存信息。输入2n个数据,并且储存当前座号。将2n个成绩排序,例如n = 3 样例16,2,1,7,5,10

对应的排名为:1,5,6,3,4,2

题目要求,排名i的和排名2n−i+1的坐第i桌。

因为同一桌两人不分左右,所以我们转化成每个人所在的大桌。

所以每一个人对应的所在的桌子为:1,2,1,3,3,2

我们是需要转成1,1,2,2,3,3的形式,求最少移动次数。

最长不下降子序列长度即为最多有这么多人不需要移动。

所以答案为:2∗n − 最长不下降子序列长度。数据过大,正解O(nlogn)的LIS。
*刚开始我的代码只得了20分,有五组数据没过,在大佬的提醒下发现是我数组开小了。。。

代码 :

#include <stdio.h>
#include <stdlib.h>
long long n,b[2000005],s[200005],min,mid,max,tail,head;
struct dalao
{
	long long score;   //储存成绩 
	long long zuo;    //储存座号 
}pp[200005];
int kk(const void *p,const void *q)
{
	return (*(struct dalao *)q).score-(*(struct dalao *)p).score;    //将成绩降序排列 
}
void er(long long target) 
{
    int left = 0;
    int right = tail; 
    while (left < right)
    { 
        int mid = (left + right) / 2;
        if (s[mid] >target) 
        {
            right = mid;
        } 
        else if (s[mid] <=target)
        {
            left = mid + 1;
        } 
    }
    s[left]= target;
}
int main()
{
	scanf("%lld",&n);
	for(int i=1;i<=2*n;i++)
	{
		scanf("%lld",&pp[i].score );
		pp[i].zuo =i;
	}
	qsort(pp+1,2*n,sizeof(struct dalao ),kk); //通过对分数的排序,获得每个分数对应的排名 
	for(int i=1;i<=n;i++)
	{
		b[pp[i].zuo ] =i;
		b[pp[2*n-i+1].zuo] =i;
	}
	s[tail++]=b[1] ;
	for(int i=2;i<=2*n;i++)
	{
		if(b[i]>=s[tail-1])	s[tail++]=b[i]; //如果不小于最后一个数,将他放在最后 
		else{
		/*	max=tail;              //找第一个比它大的数并且代替他 
			min=0;
			while(max>min)    
			{
				mid=(max+min)/2;
				if(s[mid]<=b[i]){
					min=mid+1; 
				}
				else{
					max=mid;
				}
			}
			s[min]=b[i];*/
			er(b[i]);
		}
	}
	printf("%lld",2*n-tail);
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值