ZZ菜鸡犯傻了……被旁边 gzh 神仙秒了并 D 了一番……过来写个题解。
( ext{Solution:})
离散化一下,把式子推一下:
[sum (a_i-b_i)^2=sum a_i^2+b_i^2 +sum a_icdot b_i
]
前面两个是定值,要处理最后一坨式子。
首先可以贪心地证明,顺序乘积大于乱序乘积,因为要使大的值乘的数尽量大。
于是一种 逆序对 的既视感很清晰了。但是傻逼的我竟然傻逼到不知道怎么将一个排列交换成一个排列的最小交换次数怎么求。
显然地,对一个序列的位置与值进行映射,进而映射到另一个序列中,得到的新序列交换到 ([1,2,3...]) 的最小交换次数就是答案。
这一步其实相当于将一列火柴的位置映射到了另一列火柴上。从而将原问题转化成了一个求逆序对的经典问题。
总结:菜是原罪,我是傻逼。 膜拜 gzh 神仙 Orz
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN=3e5+10;
const int mod=1e8-3;
int a[MAXN],b[MAXN];
int A[MAXN],B[MAXN],pos[MAXN];
int Acnt,Bcnt,Alen,Blen,Ccnt,Clen;
int ls[MAXN],rs[MAXN],L[MAXN],R[MAXN],sum[MAXN],rt,node;
inline void pushup(int x){sum[x]=sum[ls[x]]+sum[rs[x]];}
struct Qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq{int x,y;}q[MAXN];
inline int getposA(int x){return lower_bound(A+1,A+Alen+1,x)-A;}
inline int getposB(int x){return lower_bound(B+1,B+Blen+1,x)-B;}
void build(int &x,int l,int r){
x=++node;
L[x]=l;R[x]=r;
if(l==r)return;
int mid=(l+r)>>1;
build(ls[x],l,mid);
build(rs[x],mid+1,r);
pushup(x);
}
void change(int x,int pos,int v){
if(L[x]==R[x]){
sum[x]=v;
return;
}
int mid=(L[x]+R[x])>>1;
if(pos<=mid)change(ls[x],pos,v);
else change(rs[x],pos,v);
pushup(x);
}
int query(int x,int l,int r){
if(L[x]>=l&&R[x]<=r)return sum[x];
int mid=(L[x]+R[x])>>1;
int res=0;
if(l<=mid)res+=query(ls[x],l,r);
if(mid<r)res+=query(rs[x],l,r);
return res;
}
inline long long Abs(long long x){
if(x<0)x=-x;
return x;
}
int n,qcnt;
signed main(){
scanf("%lld",&n);
long long ans=0;
for(int i=1;i<=n;++i)scanf("%lld",&a[i]);
for(int i=1;i<=n;++i)scanf("%lld",&b[i]);
for(int i=1;i<=n;++i)A[++Acnt]=a[i],B[++Bcnt]=b[i];
sort(A+1,A+Acnt+1);sort(B+1,B+Bcnt+1);
Alen=unique(A+1,A+Acnt+1)-A-1;
Blen=unique(B+1,B+Bcnt+1)-B-1;
for(int i=1;i<=n;++i){
a[i]=getposA(a[i]);
b[i]=getposB(b[i]);
}
build(rt,1,n);
for(int i=1;i<=n;++i)pos[a[i]]=i;
for(int i=1;i<=n;++i)b[i]=pos[b[i]];
for(int i=1;i<=n;++i){
ans+=query(rt,b[i]+1,n);
change(rt,b[i],1);
ans%=mod;
}
printf("%lld
",ans);
return 0;
}