您的位置:首页 > 编程语言 > C语言/C++

【NOIP2013提高组】火柴排队

2016-08-01 17:08 567 查看


题目大意:给你两个有序数组a,b并定义a,b间的距离为∑(ai-bi)^2,要求交换a或者b中的某些元素的位置使得a,b间距离最小。

由于∑(ai-bi)^2=∑(ai^2)+∑(bi^2)-2*∑aibi;而由于题目给定了ai,bi的值,所以∑(ai^2)、∑(bi^2)是定值,要求原式最小就需要∑aibi最大。

而根据排序不等式原理,∑aibi最大值是ai,bi的顺序和。

所以先把ai按照高度排好序,bi也按照高度排好序。题目所求就是排好序的ai和bi编号要求1~6一一对应时的排序次数。

用一个数组记录ai,bi编号间的对应关系,再求逆序对个数即可。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdlib>
#include<cstring>
#define mo 99999997
#define maxn 100010
using namespace std;
typedef long long LL;
int n;
struct data
{
int v,id;
}A[maxn],B[maxn];

bool cmp(data a,data b)
{
return a.v<b.v;
}

int x[maxn],t[maxn];

LL merge_sort(int x,int y,int *a)
{
if(x>=y)return 0;
int m=x+y>>1;
LL t1=merge_sort(x,m,a);
LL t2=merge_sort(m+1,y,a);
LL t3=0;

int i=x,j=m+1,k=x;
while(i<=m && j<=y)
{
if(a[i]>a[j])
{
t[k++]=a[j++];
t3=(t3%mo+(m-i+1)%mo)%mo;
}
else
{
t[k++]=a[i++];
}
}

while(i<=m)t[k++]=a[i++];
while(j<=y)t[k++]=a[j++];

for(int i=x;i<=y;i++)
a[i]=t[i];

return (t1+t2+t3)%mo;
}

int main()
{
//freopen("match.in","r",stdin);
//freopen("match.out","w",stdout);

scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&A[i].v);
A[i].id=i;
}
for(int i=1;i<=n;i++)
{
scanf("%d",&B[i].v);
B[i].id=i;
}

sort(A+1,A+n+1,cmp);
sort(B+1,B+n+1,cmp);

for(int i=1;i<=n;i++)
x[A[i].id]=B[i].id;

LL ans=merge_sort(1,n,x);

cout<<ans<<endl;

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息