题目描述 题目连接
在家上了一个多月的网课,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个整数,表示从左到右每一张桌子上同学的成绩
输出
输出一个整数表示最少需要几个同学出列调整。
输入
3
16 2 1 7 5 10
输出
2
解题思路来自题目来源网站:本题首先计算每个人的排名例如n = 3样例:
16,2,1,7,5,10
对应的排名为:
1,5,6,3,4,2
所以每一个人对应的所在的桌子为:
1,2,1,3,3,2
我们是需要转成
1,1,2,2,3,3
的形式,求最少移动次数。
最长不下降子序列长度即为最多有这么多人不需要移动。
所以答案为:2*n - 2∗n − 最长不下降子序列长度
代码:
本题最大数据规模达105所以O(N*N)的LIS对部分数据通过不了,先贴上这种方法的代码:
#include<cstdio>
#include<algorithm>
using namespace std;
struct node{
int grade;
int pos;
int seat;
}a[100010];
bool cmp(node a,node b){
return a.grade > b.grade;
}
bool cmp1(node a,node b){
return a.pos < b.pos;
}
int main(void){
int N;
scanf("%d",&N);
for(int i = 0;i < N * 2;i++){
scanf("%d",&a[i].grade);
a[i].pos = i;
}
sort(a,a+2*N,cmp);
for(int i = 0; i < N;i++){
a[i].seat = i + 1;
a[2 * N-i-1].seat = i + 1;
}
sort(a,a+2*N,cmp1);
int dp[100010];
int ans = 0;
for(int i = 0; i < 2*N;i++){
dp[i] = 1;
for(int j = 0; j < i ;j++){
if(a[i].seat >= a[j].seat &&dp[j]+1>dp[i])
dp[i] = dp[j] + 1;
}
ans = max(ans,dp[i]);
}
printf("%d",2 * N - ans);
return 0;
}
所以采用时间复杂度为O(Nlog(N))的LIS,主要通过动态数组来维护最长不下降子序列,如果当前的数比动态数组最后一个元素大直接加在末尾,否则去替换动态数组中第一个比他大的数,配合二分法的使用降低时间复杂度。
最长不下降子序列算法讲解
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
struct node{
int grade;
int pos;
int seat;
}a[200010];
int b[200010] = {0};
bool cmp(node a,node b){
return a.grade > b.grade;
}
bool cmp1(node a,node b){
return a.pos < b.pos;
}
vector<int> vt;
int main(void){
int N;
scanf("%d",&N);
for(int i = 0;i < N * 2;i++){
scanf("%d",&a[i].grade);
a[i].pos = i;
}
sort(a,a+2*N,cmp);
for(int i = 0; i < N;i++){
a[i].seat = i + 1;
a[2 * N-i-1].seat = i + 1;
}
sort(a,a+2*N,cmp1);
for(int i = 0; i < 2*N;i++){
if(vt.size() == 0 || a[i].seat >= vt[vt.size()-1])
vt.push_back(a[i].seat);
else{
*(upper_bound(vt.begin(),vt.end(),a[i].seat)) = a[i].seat;
}
}
printf("%d",2 * N - vt.size());
return 0;
}