[NOIP2013]火柴排队

这道题让求的是令
$ sum _{i=1} ^{i<=n} (a[i]-b[i])^2 $

最小的最少移动次数。
把这个式子拆开,

$ sum _{i=1} ^{i<=n} a[i]2+b[i]2-2*a[i]*b[i] $
有个喜闻乐见的东西叫排序不等式。

设有两组数a1,a2,……an和b1,b2,……bn,满足a1≤a2≤……≤an,b1≤b2≤……≤bn,c1,c2,……cn是b1,b2,……bn的乱序排列,则有a1bn+a2bn-1+……+anb1≤a1c1+a2c2+……+ancn≤a1b1+a2b2+anbn,当且仅当a1=a2=……=an或b1=b2=……=bn时等号成立。一般为了便于记忆,常记为:反序和≤乱序和≤顺序和.
摘自百度百科

然后就可以知道让a数组中的第i个和b数组中的第i个相对应即可。用求逆序对的求一下就行了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
const int mod=99999997,N=100005;
int n,a[N],b[N],loca[N],locb[N],t[N],c[N],ans;
inline int rd() {
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)&&ch!='-')ch=getchar();
	if(ch=='-') f=-1,ch=getchar();
	while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
	return x*f;
}
void add(int i) {for(;i<=n;i+=i&-i) t[i]=(t[i]+1)%mod;}
int query(int i) {int ans=0;for(;i;i-=i&-i) ans=(ans+t[i])%mod;return ans;}
bool cmp1(int x,int y){return a[x]<a[y];}
bool cmp2(int x,int y){return b[x]<b[y];}
int main() {
	n=rd();
	for(int i=1;i<=n;i++) a[i]=rd(),loca[i]=i;
	for(int i=1;i<=n;i++) b[i]=rd(),locb[i]=i;
	sort(loca+1,loca+1+n,cmp1);
	sort(locb+1,locb+1+n,cmp2);
	for(int i=1;i<=n;i++) c[loca[i]]=locb[i];
	for(int i=1;i<=n;i++) add(c[i]),ans+=i-query(c[i]),ans%=mod;
	cout<<ans;
}
我是咸鱼。转载博客请征得博主同意Orz
原文地址:https://www.cnblogs.com/sdfzhsz/p/9630184.html