首先我们对两个数组排序,对齐每位,然后记录一个火柴对应的另一个火柴,这时我们得到了一个序列:第i根火柴需要被放到第j个位置,然后原来火柴是按升序排序的,这时需要计算逆序对,也就是交换的最少次数
树状数组 x[i],y[i]:编号,然后z[x[i]]=y[i]:第一列第x[i]根火柴应该对应第二列第y[i]根火柴,也就是说x[i]应该被放到y[i],因为第二列要对应的火柴在y[i]
因为最先开始火柴是按升序排列,所以求逆序对就可以了
#include<iostream> #include<algorithm> #include<cstdio> using namespace std; typedef long long ll; const ll inf=99999997; int n; ll a[100010],b[100010],x[100010],y[100010],tree[600010],z[100010]; inline bool cp1(int x,int y){return a[x]<a[y];} inline bool cp2(int x,int y){return b[x]<b[y];} inline void add(int x) { for(int t=x;t<=n;t+=(t&(-t))) tree[t]++; } inline ll sum(int x) { ll ret=0; for(int t=x;t;t-=(t&(-t))) ret+=tree[t]; return ret; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",a+i); x[i]=y[i]=i; } for(int i=1;i<=n;i++) scanf("%d",b+i); sort(x+1,x+n+1,cp1); sort(y+1,y+n+1,cp2); for(int i=1;i<=n;i++) { z[x[i]]=y[i]; } ll ans=0; for(int i=1;i<=n;i++) { ans+=i-sum(z[i])-1;add(z[i]); ans%=inf; } printf("%lld ",ans); return 0; }