[题解]P1966 [NOIP 2013 提高组] 火柴排队

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;
}
posted @ 2025-07-23 17:02  Sinktank  阅读(43)  评论(0)    收藏  举报
★CLICK FOR MORE INFO★ TOP-BOTTOM-THEME
Enable/Disable Transition
Copyright © 2023 ~ 2025 Sinktank - 1328312655@qq.com
Illustration from 稲葉曇『リレイアウター/Relayouter/中继输出者』,by ぬくぬくにぎりめし.