题目: 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度。 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同,
两列火柴之间的距离定义为: ∑(ai-bi)^2其中 ai 表示第一列火柴中第 i 个火柴的高度,bi 表示第二列火柴中第 i 个火柴的高度。
每列火柴中相邻两根火柴的位置都可以交换,请你通过交换使得两列火柴之间的距离最小。请问得到这个最小的距离,最少需要交换多少次?如果这个数字太大,请输出这个最小交换次数对
99,999,997 取模的结果。
分析:
我们观察距离的定义:
所以我们要求sigma(a[i]*b[i])的最大值
显然让a中最大的乘以b中最大的可以得到最大值,而我们同时交换两个序列中的数字等价于一个序列不动,交换另一个序列中的数字
那么我们就可以构造出一个数组c,c[i]代表a序列不动,b序列中的第i个数字要移动到位置c[i]上,此时c中的逆序对个数就是我们的最小交换次数
可以用归并排序或者树状数组求
代码(树状数组):
#include<bits/stdc++.h>
#define ll long long
using namespace std;
#define mod 99999997
long long tr[100010];
const int N=100005;
int n;
int bb[N];
void add(int k,ll num)
{
while(k<=n)
{
tr[k]=(tr[k]%mod+num%mod)%mod;
k+=k&-k;
}
}
int read(int k)
{
ll sum=0;
while(k)
{
sum=(sum%mod+tr[k]%mod)%mod;
k-=k&-k;
}
return sum;
}
struct node
{
int val,pos;
}aa[100010];
bool cmp(node a,node b) {return a.val < b.val;}
struct premu1
{
long long val;
int num;
}a[N];
struct premu2
{
int num;
long long val;
int tree;
}b[N];
bool cmpa(premu1 x,premu1 y) {return x.val<y.val;}
bool cmpb(premu2 x,premu2 y) {return x.val<y.val;}
bool cmpc(premu2 x,premu2 y) {return x.num<y.num;}
int sum[N];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i].val);
a[i].num=i;
}
for(int i=1;i<=n;i++)
{
scanf("%lld",&b[i].val);
b[i].num=i;
}
sort(a+1,a+n+1,cmpa);
sort(b+1,b+n+1,cmpb);
for(int i=1;i<=n;i++) b[i].tree=a[i].num;
sort(b+1,b+n+1,cmpc);
for(int i=1;i<=n;i++) sum[i]=b[i].tree;
memset(tr,0,sizeof(tr));
for(int i=1;i<=n;i++)
{
aa[i].val = sum[i];
aa[i].pos = i;
}
sort(aa+1,aa+1+n,cmp);
int cnt = 1;
for(int i=1;i<=n;i++)
{
if(i != 1 && aa[i].val != aa[i-1].val)
cnt++;
bb[aa[i].pos] = cnt;
}
ll summ = 0;
for(int i=1;i<=n;i++)
{
add(bb[i],1);
summ=(summ+(i - read(bb[i]))%(ll)99999997)%(ll)99999997;
}
printf("%lld\n",summ);
return 0;
}