码迷,mamicode.com
首页 > 其他好文 > 详细

[NOIP2013提高组]火柴排队

时间:2017-10-09 22:36:06      阅读:220      评论:0      收藏:0      [点我收藏+]

标签:分析   col   cstring   style   解题思路   表示   时间复杂度   条件   答案   

题目大意:有两排火柴,每根都有一个高度。设a、b分别表示两排火柴的高度,现在要令$\sum(a_i-b_i)^2$最小。现两排火柴已经排成一个序列,求最少交换多少次能满足条件。

解题思路:首先,只有当最大的对应最大的,次大的对应次大的,以此类推,得到的答案才可能最小。

然后我们发现,如此分析后,此题的答案与火柴实际长度无关,只要按照原来的大小顺序即可,且只需考虑对一排火柴进行交换即可。

因此我们对两组数据分别离散,然后通过第一组数据再对第二组数据再离散一遍即可。

最后其实就是求逆序对了,归并排序即可。

时间复杂度$O(n\log _2 n)$。

既然写了归并,还用什么sort(*^__^*)

C++ Code:

#include<cstdio>
#include<cstring>
using namespace std;
int n,a[100005],ans,b[100005],c[100005],ys[100005],p[100005];
void merge(int* a,int l,int r){
	int i=l,mid=l+r>>1,k=l;
	int j=mid+1;
	while(i<=mid&&j<=r){
		if(a[i]>a[j]){
			ans=(ans+mid-i+1)%99999997;
			c[k++]=a[j++];
		}
		else
		c[k++]=a[i++];
	}
	while(i<=mid)c[k++]=a[i++];
	while(j<=r)c[k++]=a[j++];
	for(i=l;i<=r;++i)a[i]=c[i];
}
void mergesort(int* a,int l,int r){
	if(l!=r){
		int m=l+r>>1;
		mergesort(a,l,m);
		mergesort(a,m+1,r);
		merge(a,l,r);
	}
}
void merge_sort(int* a,int l,int r){
	ans=0;
	mergesort(a,l,r);
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i)scanf("%d",&a[i]);
	memcpy(p,a,sizeof p);
	merge_sort(p,1,n);
	for(int i=1;i<=n;++i)
	ys[p[i]]=i;
	for(int i=1;i<=n;++i)a[i]=ys[a[i]];
	for(int i=1;i<=n;++i)scanf("%d",&b[i]);
	memcpy(p,b,sizeof p);
	merge_sort(p,1,n);
	for(int i=1;i<=n;++i)
	ys[p[i]]=i;
	for(int i=1;i<=n;++i)b[i]=ys[b[i]];
	for(int i=1;i<=n;++i)
	ys[a[i]]=i;
	for(int i=1;i<=n;++i)b[i]=ys[b[i]];
	merge_sort(b,1,n);
	printf("%d\n",ans);
	return 0;
}

 

[NOIP2013提高组]火柴排队

标签:分析   col   cstring   style   解题思路   表示   时间复杂度   条件   答案   

原文地址:http://www.cnblogs.com/Mrsrz/p/7642765.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!