[NOIP2013]火柴排队(逆序对)

题目

思路

逆序对只会猜结论

显然需要先猜个结论:(a)数列第(i)大对应(b)数列第(i)大时平方和有最小值

通过交换法,需证明:((b_i-a_j)^2+(b_j-a_i)^2 > (b_i-a_i)^2+(b_j-a_j),(j<i))

上式化简得:(a_j<a_i),显然成立

(pa_i)表示(i)这个数在(a)数列的哪个位置,(pb_i)同理

设数列(b_{pa_i}=pb_i),由于需要位置对齐,需要(b_{pa_i}=pa_i),即(b_i=i)

问题变成求b序列经过多少次交换变成有序序列

显然逆序对

Code

#include<bits/stdc++.h>
#define N 200005
#define lowbit(x) ((x)&(-(x)))
#define Min(x,y) ((x)<(y)?(x):(y))
#define Max(x,y) ((x)>(y)?(x):(y))
using namespace std;
typedef long long ll;
const ll mod = 99999997; 
int n,b[N],c[N];
struct Node
{
	int a,loc;
}A[N],B[N];

template <class T>
void read(T &x)
{
	char c; int sign=1;
	while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
	while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign;
}
bool cmp(Node a,Node b) { return a.a<b.a; }
void update(int x,int v) { for(;x<N;x+=lowbit(x)) c[x]+=v; }
int query(int x) { int ret=0; for(;x;x-=lowbit(x)) ret+=c[x]; return ret; } 
int main()
{
	read(n);
	for(int i=1;i<=n;++i) read(A[i].a),A[i].loc=i;
	for(int i=1;i<=n;++i) read(B[i].a),B[i].loc=i;
	sort(A+1,A+n+1,cmp);
	sort(B+1,B+n+1,cmp);
	for(int i=1;i<=n;++i) b[A[i].loc]=B[i].loc;
	ll ans=0;
	for(int i=n;i>=1;--i)
	{
		ans=(ans+query(b[i]-1))%mod;
		update(b[i],1);
	}
	cout<<ans<<endl;
	return 0;
}
原文地址:https://www.cnblogs.com/Chtholly/p/11779211.html