[FROM LUOGU]火柴排隊

傳送門

爲什麼是提高+/省選- 啊(

SOL
其實怎樣的順序最優是很顯然的,不過這裏我還是給出一個證明
要證明aiaibibi按大小順序一一對應爲最優,我們只需證明一個子問題即可
設在排過序後的火柴序列中選取i<ji<j,那麼ai<aj,bi<bjai<aj,bi<bj,若調換其位置,那麼答案的變化即爲:
delta=(aibi)2+(ajbj)2(aibj)2(ajbi)2delta=(ai-bi)^2+(aj-bj)^2-(ai-bj)^2-(aj-bi)^2
化簡可得
delta=2(bjbi)(ajai)>0delta=2(bj-bi)*(aj-ai)>0
所以調換後的答案更大,顯然不優
利用數學歸納法可以證明整個序列具有同樣的性質
證畢

接下來的操作就比較容易了
由於火柴只能相鄰的直接交換,因此每根火柴的交換次數即爲其逆序對個數,於是樹狀數組維護即可

代碼:

#include<bits/stdc++.h>
#define re register
using namespace std;
inline int rd(){
	int data=0;static char ch=0;ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))data=(data<<1)+(data<<3)+(ch^48),ch=getchar();
	return data;
}
const int mod=99999997,N=1e5+5;
struct matches{int hi,id,pa;}a[N],b[N];
inline bool cmp1(const matches&x,const matches&y){return x.hi<y.hi;}
inline bool cmp2(const matches&x,const matches&y){return x.id<y.id;}
int n,c[N],ans;
#define lb(x) (x&-x)
inline void edit(int p,int k){for(;p<=n;p+=lb(p))c[p]+=k;}
inline int ask(int p,int ret=0){for(;p;p-=lb(p))ret+=c[p];return ret;}
signed main(){
	n=rd();
	for(int re i=1;i<=n;++i)a[i].hi=rd(),a[i].id=i;
	for(int re i=1;i<=n;++i)b[i].hi=rd(),b[i].id=i;
	sort(a+1,a+n+1,cmp1),sort(b+1,b+n+1,cmp1);
	for(int re i=1;i<=n;++i)b[i].pa=a[i].id;
	sort(a+1,a+n+1,cmp2),sort(b+1,b+n+1,cmp2);
	for(int re i=1;i<=n;++i)(ans+=i-1-ask(b[i].pa))%=mod,edit(b[i].pa,1);
	cout<<ans,exit(0);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章