深搜10:【SSL】1643.混乱的秩序——2021-05-02第四更

11 篇文章 0 订阅

深搜10:【SSL】1643.混乱的秩序

题目:

题目描述

课间操时间到了,各班都站成了一行。

本来每个班是应该按身高从低到高站队的,但是有部分同学站错了地方,使得有些同学的前面还有人比他的身高更高,这样就导致整个队形看起来很混乱。
如果每两个人出现这种情况,我们就记混乱度为1,请你计算出每个班的混乱度为多少?

输入

数据包含多个班。
每个班的第一行含有一个整数 n(0≤n<500000),表示该班的人数。
接下来n行每行有一个整数ai(0≤ai≤10^9),表示该班排队后每个同学的身高。
当某班人数为0时,输入终止,该序列无需处理。

输出

对于每个班,输出一个整数,表示该班的混乱度,每个整数占一行。

样例

输入样例
5
9 1 0 5 4
3
1 2 3
0

输出样例
6
0

思路:

首先看数据,这道题目有多个班,且一个班最多有500000人,这么大的数据如果是普通搜索别说多个班了,半个班搜完都炸了,所以一定不会用到正常的搜索方案,那么,就要用到一个思想了——分治。
分治就是不断的将当前问题分成两半,直到不能再分,通过完成一个个小问题完成最终的大问题,二分就是分治的一种。
这里要用的的是分治中的归并排序。
归并排序有点像二分,每次把z-y区间的数从中间分开,直到z=y的时候return,每次把z-y的区域分为z-m和m+1-y,用i表示z,j表示m+1,再开一个变量k=z,如下图:在这里插入图片描述
这里用A表示a[z]~a[m]的数,
用B表示a[m+1]~a[y]的数,每次比较a[i]和a[j]的大小,如果a[i]≤a[j]那么c[k++]=a[i++](k表示c数组中第k个数),当i>m或者是j>y的话就说明A或B中有一个中的数已经全部放入C中了,那么A或B中剩下的数就可以直接放进C中(剩下的数一定大于等于c[k-1]),这样一来,就可以将z-y中的数排好序了,最终就可以把1-n排好序。
再说一下,这个排序的时间复杂度和快排是一样的。
知道了这点之后,我们就可以看到一个数a[j]如果<a[i],那么因为A是升序排列,所以a[j]<a[i]就说明它小于a[i]-a[m]所有数。
既然如此,那解题思路就很明确了。
对当前班级的数据进行归并排序,然后在排序过程中累加混乱度。
做的时候并不需要担心因为数据改变导致结果和原先有差别,因为每次排序过程中区间的混乱度都已经被记下来了,而前面的区间即使位置改变也没有关系,因为在它前面的即使改了位置也依旧在它前面,并不会影响结果。

代码:

#include<bits/stdc++.h>
using namespace std;
int n,a[500010],b[500010];
long long ans;

void dfs(int z,int y)
{
	if(z==y)
		return ;
	int m=(z+y)/2;
	dfs(z,m);
	dfs(m+1,y);
	int i=z,j=m+1,k=z;
	while(i<=m&&j<=y)
	{
		if(a[i]<=a[j])
			b[k++]=a[i++];
		else
		{
			ans+=m-i+1;
			b[k++]=a[j++];
		}
	}
	while(i<=m)
		b[k++]=a[i++];
	while(j<=y)
		b[k++]=a[j++];
	for(int l=z;l<=y;l++)
		a[l]=b[l];
}
int main()
{
	ios::sync_with_stdio(false);
	while(1)
	{
	//数组不需要memset因为dfs的区间只有1-n,不会再往后,所以不清空也可以
		ans=0;
		cin>>n;
		if(n==0)
			break;
		for(int i=1;i<=n;i++)
			cin>>a[i];
		dfs(1,n);
		cout<<ans<<endl;
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值