gesp(C++六级)(4)洛谷:B3874:[GESP202309 六级] 小杨的握手问题
题目描述
小杨的班级里共有 N N N 名同学,学号从 0 0 0 至 N − 1 N-1 N−1。
某节课上,老师安排全班同学进行一次握手游戏,具体规则如下:老师安排了一个顺序,让全班 N N N 名同学依次进入教室。每位同学进入教室时,需要和 已经在教室内 且 学号小于自己 的同学握手。
现在,小杨想知道,整个班级总共会进行多少次握手。
提示:可以考虑使用归并排序进行降序排序,并在此过程中求解。
输入格式
输入包含 2 2 2 行。第一行一个整数 N N N ,表示同学的个数;第二行 N N N 个用单个空格隔开的整数,依次描述同学们进入教室的顺序,每个整数在 0 ∼ N − 1 0 \sim N-1 0∼N−1 之间,表示该同学的学号。
保证每位同学会且只会进入教室一次。
输出格式
输出一行一个整数,表示全班握手的总次数。
样例 #1
样例输入 #1
4
2 1 3 0
样例输出 #1
2
样例 #2
样例输入 #2
6
0 1 2 3 4 5
样例输出 #2
15
提示
样例解释 1:
2 2 2 号同学进入教室,此时教室里没有其他同学。
1 1 1 号同学进入教室,此时教室里有 2 2 2 号同学。 1 1 1 号同学的学号小于 2 2 2 号同学,因此他们之间不需要握手。
3 3 3 号同学进入教室,此时教室里有 1 , 2 1,2 1,2 号同学。 3 3 3 号同学的学号比他们都大,因此 3 3 3 号同学需要分别和另外两位同学握手。
0 0 0 号同学进入教室,此时教室里有 1 , 2 , 3 1,2,3 1,2,3 号同学。 0 0 0 号同学的学号比他们都小,因此 0 0 0 号同学不需要与其他同学握手。
样例解释2:
全班所有同学之间都会进行握手,因为每位同学来到教室时,都会发现他的学号是当前教室里最大的,所以他需要和教室里的每位其他同学进行握手。
对于 30 % 30\% 30% 的测试点,保证 N ≤ 100 N\le100 N≤100。
对于所有测试点,保证 2 ≤ N ≤ 3 × 1 0 5 2\le N\le3\times10^5 2≤N≤3×105。
AC代码(100分)
#include<bits/stdc++.h>
using namespace std;
/*思路: 归并排序:间复杂度为nlogn,100分
*/
const int N=3e5+10;
int n,a[N],b[N];
long long cnt=0;
//归并排序函数
void merge(int l,int r){if(l==r) return;//递归边界 //分解 int mid=(l+r)/2;merge(l,mid);//左区间 merge(mid+1,r);//右区间 //合并int i=l,j=mid+1,k=l;while(i<=mid && j<=r){if(a[i]<a[j]){ cnt+=(mid-i+1);//更新答案 b[k++]=a[j++];}else{b[k++]=a[i++];}} while(i<=mid){b[k++]=a[i++];}while(j<=r){b[k++]=a[j++];}for(int i=l;i<=r;i++){a[i]=b[i];}
}
int main(){cin>>n;for(int i=1;i<=n;i++) cin>>a[i];merge(1,n);//归并排序 cout<<cnt;return 0;
}
文末彩蛋:
点击王老师青少年编程主页有更多精彩内容