题目描述
涵涵有两盒火柴,每盒装有 $n$ 根火柴,每根火柴都有一个高度。 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间的距离定义为: $ \sum (a_i-b_i)^2$
其中 $ a_i$ 表示第一列火柴中第 $ i $ 个火柴的高度, $b_i$ 表示第二列火柴中第 $i$ 个火柴的高度。
每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对 $99,999,997 $ 取模的结果。
输入输出格式
输入格式:共三行,第一行包含一个整数 $ n$ ,表示每盒中火柴的数目。
第二行有 $ n $ 个整数,每两个整数之间用一个空格隔开,表示第一列火柴的高度。
第三行有 $n$ 个整数,每两个整数之间用一个空格隔开,表示第二列火柴的高度。
输出格式:一个整数,表示最少交换次数对 $99,999,997$ 取模的结果。
输入输出样例
说明
【输入输出样例说明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+a2bn−1+...+anb1≤a1c1+a2c2+...+ancn≤a1b1+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;
}