题解:本题主要考查逆序对,树状数组。
简要题意:两列火柴之间的距离为:
∑
(
a
i
−
b
i
)
2
\sum(a_i-b_i)^2
∑(ai−bi)2,每列火柴中相邻两根火柴的位置都可以交换,请通过交换使两列火柴之间的距离最小,求最少交换次树数。
1.贪心:我们要
∑
(
f
i
r
i
−
s
e
c
i
)
2
\sum(fir_i-sec_i)^2
∑(firi−seci)2最小,相当于要最小化
(
f
i
r
i
−
s
e
c
i
)
(fir_i−sec_i)
(firi−seci),也就是fir列第k大的元素必须和sec列中第k大的元素位置一样。
2.逆序对+归并排序:这道题目的最难点在于新建序列!按高度排列,得出他们的序号序列a,b。如样例2:
Fir:1 3 4 2->1 2 3 4 A:对应原编号为:1 4 2 3
Sec:1 7 2 4->1 2 4 7 B:对应原编号为:1 3 4 2
新的序列表示(Fir为例):第一小的数在原序列第一位,第二小的数在原序列第四位(第
k
k
k大的在原序列的位置)
所以要把元素按第k大的元素位置对应,就只用将序列A,B交换相等即可,问题就便为求逆序对数了。
代码如下:
#include<iostream>
#include<algorithm>
using namespace std;
struct N
{
long long ans,num;
}fir[222222],sec[222222];
long long n,ans;
long long a[222222],b[222222];
bool cmp(N x,N y)
{
return x.ans<y.ans;
}
void Bgui(int l,int r)
{
if(l>=r)return ;
int mid=l+r>>1;
int i=l;int j=mid+1;int k=l;
Bgui(l,mid);Bgui(mid+1,r);
while(i<=mid&&j<=r)
{
if(a[i]>a[j])
{
b[k++]=a[j++];
ans+=mid-i+1;
ans%=99999997;
}
else b[k++]=a[i++];
}
while(i<=mid) b[k++]=a[i++];
while(j<=r) b[k++]=a[j++];
for(int i=l;i<=r;i++)a[i]=b[i];
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>fir[i].ans;
fir[i].num=i;
}
for(int i=1;i<=n;i++)
{
cin>>sec[i].ans;
sec[i].num=i;
}
sort(fir+1,fir+1+n,cmp);
sort(sec+1,sec+1+n,cmp);
for(int i=1;i<=n;i++)
a[fir[i].num]=sec[i].num;
Bgui(1,n);
cout<<ans<<endl;
return 0;
}