NOIP2013 火柴排队

题目描述

涵涵有两盒火柴,每盒装有 $n$ 根火柴,每根火柴都有一个高度。 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: $ \sum (a_i-b_i)^2$

其中 $ a_i$ 表示第一列火柴中第 $ i $ 个火柴的高度, $b_i$ 表示第二列火柴中第 $i$ 个火柴的高度。

每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 $99,999,997 $ 取模的结果。

输入输出格式

输入格式:

共三行,第一行包含一个整数 $ n$ ,表示每盒中火柴的数目。

第二行有 $ n $ 个整数,每两个整数之间用一个空格隔开,表示第一列火柴的高度。

第三行有 $n$ 个整数,每两个整数之间用一个空格隔开,表示第二列火柴的高度。

输出格式:

一个整数,表示最少交换次数对 $99,999,997$ 取模的结果。

输入输出样例

输入样例#1: 复制
4
2 3 1 4
3 2 1 4
输出样例#1: 复制
1
输入样例#2: 复制
4
1 3 4 2
1 7 2 4
输出样例#2: 复制
2

说明

【输入输出样例说明1】

最小距离是 $ 0$ ,最少需要交换 $1$ 次,比如:交换第 $1 $ 列的前 $ 2$ 根火柴或者交换第 $2$ 列的前 $2 $ 根火柴。

【输入输出样例说明2】

最小距离是 $10$ ,最少需要交换 $ 2 $ 次,比如:交换第 $ 1$ 列的中间 $ 2 $ 根火柴的位置,再交换第 $ 2$ 列中后 $2$ 根火柴的位置。

【数据范围】

对于 $10\%$ 的数据, $1 ≤ n ≤ 10$ ;

对于 $30\%$ 的数据, $1 ≤ n ≤ 100$ ;

对于 $60\%$ 的数据, $1 ≤ n ≤ 1,000$ ;

对于 $100\%$ 的数据, $1 ≤ n ≤ 100,000,0 ≤$ 火柴高度 $≤ maxlongint$


首先要知道一个叫做排序不等式的东西,总的来说就是反序和≤乱序和≤逆序和
详细的表述如下:
给出三个数列
a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an
b 1 , b 2 , . . . , b n b_1,b_2,...,b_n b1,b2,...,bn
c 1 , c 2 , . . . , c n c_1,c_2,...,c_n c1,c2,...,cn
且满足
a 1 < a 2 < . . . < a n a_1<a_2<...<a_n a1<a2<...<an
b 1 < b 2 < . . . < b n b_1<b_2<...<b_n b1<b2<...<bn
数列 c 1 , c 2 , . . . , c n c_1,c_2,...,c_n c1,c2,...,cn是随机排列后的数列b
那么有
a 1 b n + a 2 b n − 1 + . . . + a n b 1 ≤ a 1 c 1 + a 2 c 2 + . . . + a n c n ≤ a 1 b 1 + a 2 b 2 + . . . + a n c n a_1b_n+a_2b_{n-1}+...+a_nb_1≤a_1c_1+a_2c_2+...+a_nc_n≤a_1b_1+a_2b_2+...+a_nc_n a1bn+a2bn1+...+anb1a1c1+a2c2+...+ancna1b1+a2b2+...+ancn

证明百度
题中式子$ \sum (a_i-b_i)2=\sum(a_i2-2a_ib_i+b_i^2)$
显然 ∑ ( a i 2 + b i 2 ) \sum(a_i^2+b_i^2) (ai2+bi2)是常数,那么我们要“距离”最小,只需要让 ∑ ( a i b i ) \sum(a_ib_i) (aibi)最大
由排序不等式可得,要让 a i a_i ai b i b_i bi有序时,是最大的
但是我们并不需要让他们两个绝对的有序,只需要相对有序
让两队火柴中的一一对应即可
所以就需要离散化一下,开一个a_hash和b_hash,拷贝a和b中的元素,排序,然后一一把a,b中的元素对应成它们序号
然后再把b中的顺序当成排好序的,把a中的再对应一下之后再去寻找逆序对
开了这些数组之后空间算出来大概38M,可过
全部时间复杂度 O ( 5 n l o g 2 n + n ) O(5nlog_2n+n) O(5nlog2n+n)
2个nlogn是排序,2个是离散化,一个n是把b当成有序的之后转换a,一个nlogn是最后归并排序求逆序对
当然也可以用树状数组/线段树求逆序对,不过归并排序代码难度还是比较小的,所以就用了归并排序
有空再打一下树状数组和线段树的吧(咕咕咕)


代码

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define For(i,l,r) for(int i=l;i<=r;++i)
#define MAXN 1000010
#define M 99999997
#define mid ((l+r)>>1)
using namespace std;
long long read()
{
	char c;
	bool t=0;
	long long a=0;
	while((c=getchar())==' '||c=='\n'||c=='r');
	if(c=='-')
	{
		t=1;
		c=getchar();
	}
	while(isdigit(c))
	{
		a*=10;
		a+=(c-'0');
		c=getchar();
	}
	return a*(t?-1:1);
}
int n,mmap[MAXN],temp[MAXN];
long long a[MAXN],b[MAXN],a_hash[MAXN],b_hash[MAXN],ans;
int finda(long long x)
{
	return lower_bound(a_hash+1,a_hash+n+1,x)-a_hash;
}
int findb(long long x)
{
	return lower_bound(b_hash+1,b_hash+n+1,x)-b_hash;
}
void merge(int l,int r)
{
	int l1=l,l2=mid+1,r1=mid,r2=r,tl=l;
	while(l1<=r1&&l2<=r2)
	{
		if(a[l1]<a[l2])
		{
			temp[tl]=a[l1];
			++tl;
			++l1;
		}
		else//逆序对 
		{
			ans+=((r1-l1+1)%M);
			ans%=M;
			temp[tl]=a[l2];
			++tl;
			++l2;
		}
	}
	while(l1<=r1)
	{
		temp[tl]=a[l1];
		tl++;l1++;
	}
	while(l2<=r2)
	{
		temp[tl]=a[l2];
		tl++;l2++;
	}
	while(l<=r)
	{
		a[l]=temp[l];
		++l;
	}
}
void msort(int l,int r)
{
	if(r-l>1)
	{
		msort(l,mid);
		msort(mid+1,r);
	}
	merge(l,r);
}
int main()
{
	n=read();
	For(i,1,n)
	 a[i]=read();
	For(i,1,n)
	 b[i]=read();
	memcpy(a_hash,a,sizeof a);memcpy(b_hash,b,sizeof b);
	sort(a_hash+1,a_hash+n+1);sort(b_hash+1,b_hash+n+1);
	For(i,1,n)
	{
		a[i]=finda(a[i]);
		b[i]=findb(b[i]);
		mmap[b[i]]=i;
	}
	For(i,1,n)
	 a[i]=mmap[a[i]];
	msort(1,n);
	printf("%lld",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
noip2013普及组初赛是全国信息学奥林匹克联赛的一场选拔赛。该比赛旨在选拔初学者,对编程和算法有一定基础的学生,通过比赛形式来考察他们的知识水平和解题能力。 比赛题目通常会涉及各个领域的算法和数据结构,如图论、动态规划、数论等。题目难度逐步增加,从简单的输出结果,到复杂的程序设计与代码实现,考察选手的逻辑思维和编程能力。 参赛选手需要通过自己的思考和编程实现来解决题目,同时时间也是一个重要因素。比赛中,选手需要在规定的时间内独立完成所有题目,对于复杂的题目需要迅速想出解题思路并进行编码。因此,在比赛中,选手的临场发挥和解题速度也是需要考虑的因素。 noip2013普及组初赛的结果将作为选拔阶段的一个重要依据,选出表现出色的选手进入到更高阶段的比赛,对于他们来说,这是一次展示自己实力的机会。 此外,noip2013普及组初赛,也给了参赛选手一个交流的平台。选手们可以通过比赛结交同好,相互切磋,共同进步。同时,比赛结束后,还有详细的解题分析和讲解,有助于参赛选手对自己在比赛中的不足进行反思与改进。 总之,noip2013普及组初赛是一个考察学生编程和算法能力的选拔赛,通过比赛的形式来选拔出优秀的选手。这对于参赛选手来说,是一次展示自己才华的机会,也是一个展示自己实力和提高自己能力的平台。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值