LOJ2609. NOIP2013 火柴排队
题目大意:
给你两个数列,定义权值
∑
i
=
1
n
(
a
i
−
b
i
)
2
\sum_{i=1}^n(a_i-b_i)^2
∑i=1n(ai−bi)2
问最少的操作次数,最小化权值
首先需要发现几个性质
- 最小权值满足任意i,j不存在 a i > a j , b i < b j a_i>a_j,b_i<b_j ai>aj,bi<bj
- 只需要改变一个序列的顺序就足够了
- 把一个序列排序成有序的最少操作次数是逆序对个数
然后就可以随便做了
#include<bits/stdc++.h>
using namespace std;
#define N 100010
#define Mod 99999997
struct Node{int val,id;}a[N],b[N];
int n,match[N];
bool cmp(Node a,Node b){return a.val<b.val;}
int t[N];
int add(int a,int b){return (a+b)%Mod;}
void add(int x){while(x<=n)t[x]++,x+=x&(-x);}
int query(int x){int res=0;while(x)res=add(res,t[x]),x-=x&(-x);return res;}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)a[i].id=b[i].id=i;
for(int i=1;i<=n;i++)scanf("%d",&a[i].val);
for(int i=1;i<=n;i++)scanf("%d",&b[i].val);
sort(a+1,a+n+1,cmp);
sort(b+1,b+n+1,cmp);
for(int i=1;i<=n;i++)match[a[i].id]=b[i].id;
int ans=0;
for(int i=n;i>=1;i--){
ans=add(ans,query(match[i]));
add(match[i]);
}
printf("%d",ans);
return 0;
}