[题解]P1966 [NOIP 2013 提高组] 火柴排队
结论:当且仅当\(a\)中第\(i\)小和\(b\)中第\(i\)小配对时,答案最优。
证明:我们取\(a_i<a_j,b_i<b_j\),即证明\((a_i,b_i)(a_j,b_j)\)这种配对方案,一定比\((a_i,b_j)(a_j,b_i)\)更优。
也即证明:
\[(a_i-b_i)^2+(a_j-b_j)^2>(a_i-b_j)^2+(a_j-b_i)^2
\]
整理上式并因式分解:
\[a_ib_i+a_jb_j-a_ib_j-a_jb_i>0\\
(a_i-a_j)(b_i-b_j)>0\]
由于\(a_i>a_j,b_i>b_j\),所以上式成立。故得证。
(实际上面的命题就是排序不等式的特例,当且仅当\(a_i\)全部相等或者\(b_i\)全部相等时取等)
进一步地,由于\(a\)和\(b\)内元素分别互不相等,所以最终配对方案是固定的。问题在于顺序。
显然\(b\)的交换与\(a\)在相应位置的交换是等价的,所以简化题意为\(b\)不动,仅交换\(a\)的元素。
根据上面的结论,我们可以通过排序很容易地计算出\(a_i\)最终变到的位置,记作\(c_i\)。
原下标\(1,2,3,\dots,n\),变化到\(c_1,c_2,c_3,\dots,c_n\)。
那答案显然就是\(c\)的逆序对数量了,这是因为从后者变到前者每次操作减少一个逆序对。
时间复杂度\(O(n\log n)\)。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10,P=1e8-3;
int n,c[N],s[N],ans;//to[i]:a[i]最终到哪一位
struct Elem{int id,v;}a[N],b[N];
bool cmp(Elem a,Elem b){return a.v<b.v;}
inline int lb(int x){return x&-x;}
void chp(int x,int v){
for(;x<=n;x+=lb(x)) s[x]+=v;
}
int query(int x){
int ans=0;
for(;x;x-=lb(x)) ans+=s[x];
return ans;
}
signed main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i].v,a[i].id=i;
for(int i=1;i<=n;i++) cin>>b[i].v,b[i].id=i;
sort(a+1,a+1+n,cmp),sort(b+1,b+1+n,cmp);
for(int i=1;i<=n;i++) c[b[i].id]=a[i].id;
for(int i=n;i;i--){
ans+=query(c[i]);
chp(c[i],1);
}
cout<<ans%P<<"\n";
return 0;
}
浙公网安备 33010602011771号