\(Description\)
题面
有两列火柴,每个火柴有一个高度,定义两列火柴之间的距离为\(\sum\limits_{i=1}^n (a_i-b_i)^2\),其中\(a_i\)表示第一列火柴中第\(i\)个火柴的高度,\(b_i\)表示第二列火柴中第\(i\)个火柴的高度
可以交换一列中任意两根相邻火柴的位置,使得最终两列火柴距离最小,求最少交换次数
\(Solution\)
想让两列火柴距离最小,显然要使第一列中第\(i\)高的火柴对应第二列中第\(i\)高的火柴,证明略。
分别开两个数组\(c,d\),\(c[i]\)表示在\(a\)数组中第\(i\)大的数所在的位置(如果出现相同的数按照下标排序)
比如下面这个例子,理解一下
c | 1 | 4 | 5 | 2 | 3 |
---|---|---|---|---|---|
a | 1 | 3 | 5 | 1 | 2 |
\(d[i]\)同理表示\(b\)数组
这实际是一种离散化,不过我们常用的离散化\(c[i]\)表示\(i\)的排名,这个离散化\(c[i]\)表示排名为\(i\)所在的下标
然后令\(p[c[i]]=d[i]\),表示他们之间的对应关系
比如下面这样
c | 1 | 4 | 5 | 2 | 3 |
---|---|---|---|---|---|
d | 3 | 2 | 1 | 5 | 4 |
p | 3 | 5 | 4 | 2 | 1 |
最终要求在各自数组中排名相同的在同一位置,即\(p[i]=i\)
所以要把\(p\)数组变成一个升序数列,假如\(p[5]=3,p[3]=5\)表示表示排名为\(i\)的元素在\(a\)中是第\(5\)个,在\(b\)中是第\(3\)个,排名为\(j\)的元素在\(a\)中是第\(3\)个,在\(b\)中是第\(5\)个
结论:使\(p\)数组由无序变为升序(每次只能交换相邻两个数),最小操作个数是逆序对数量之和。
因此对\(p\)数组求逆序对之和就行
\(Code\)
#include<cstdio> #include<iostream> #include<algorithm> #define re register #define maxn 101010 #define ll long long #define mod 99999997 #define ls p<<1 #define rs p<<1|1 using namespace std; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } ll ans; int len1,len2; ll sums[maxn<<2]; int a[maxn],b[maxn],p[maxn],n; struct PCC{ int id,num; }c[maxn],d[maxn]; bool cmp(PCC A,PCC B) { if(A.num!=B.num) return A.num<B.num; return A.id<B.id; } void DCZ1() { sort(c+1,c+n+1,cmp); for(re int i=1;i<=n;++i) a[i]=c[i].id; } void DCZ2() { sort(d+1,d+n+1,cmp); for(re int i=1;i<=n;++i) b[i]=d[i].id; } void push_up(int p) { sums[p]=sums[ls]+sums[rs]; } void insert(int p,int l,int r,int k) { if(l==r) { sums[p]++; return ; } int mid=(l+r)>>1; if(k<=mid) insert(ls,l,mid,k); else insert(rs,mid+1,r,k); push_up(p); } int query(int p,int l,int r,int k) { int tmp=0; if(l==r) { if(l<=k) tmp+=sums[p]; return tmp; } int mid=(l+r)>>1; if(k>mid) tmp+=sums[ls],tmp+=query(rs,mid+1,r,k); else tmp+=query(ls,l,mid,k); return tmp; } void solve() { for(re int i=1;i<=n;++i) { ll tmp=(i-1)-query(1,1,n,p[i]); tmp=(tmp%mod+mod)%mod; ans=(ans+tmp)%mod; insert(1,1,n,p[i]); } } int main() { n=read(); for(re int i=1;i<=n;++i) a[i]=read(),c[i].num=a[i],c[i].id=i; for(re int i=1;i<=n;++i) b[i]=read(),d[i].num=b[i],d[i].id=i; DCZ1(),DCZ2(); for(re int i=1;i<=n;++i) p[a[i]]=b[i]; solve(); printf("%lld\n",ans); return 0; }