【容斥原理】【推导】【树状数组】Gym - 101485G - Guessing Camels

题意:给你三个1~n的排列a,b,c,问你在 (i,j)(1<=i<=n,1<=j<=n,i≠j),有多少个有序实数对(i,j)满足在三个排列中,i都在j的前面。

暴力求的话是三维偏序,相对比较困难。但是我们可以用一些简单的方法。

设在a中i在j前面的有序实数对数为A,b中为B,c中为C。(其实显然A=B=C=n*(n-1)/2)

要求的即为A∩B∩C。

利用容斥原理A+B+C-A∩B-A∩C-B∩C+A∩B∩C=A∪B∪C ①,以及Ω-A∪B∪C=A∩B∩C ②可容易求得。(显然Ω=n*(n-1))

②式怎么来的呢?显然,在三个序列中均满足i在j前面的有序实数对(i,j),必然与在三个序列中都未出现的有序实数对(j,i)一一对应,证毕。

而A∩B、A∩C、B∩C都可以通过二维偏序(排序+树状数组)求得。

所以最后答案就是(n*(n-1)-(n*(n-1)/2*3-A∩B-A∩C-B∩C))/2。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int n;
int d[200005];
void Update(int p){for(;p<=n;p+=(p&(-p))) ++d[p];}
int Query(int p){int res=0; for(;p;p-=(p&(-p))) res+=d[p]; return res;}
ll A[3];
struct data{
	int x,y;
	data(const int &x,const int &y){
		this->x=x;
		this->y=y;
	}
	data(){}
}a[200005],b[200005],c[200005],p[3][200005];
bool operator < (const data &a,const data &b){
	return a.x<b.x;
}
int main(){
//	freopen("g.in","r",stdin);
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%d",&a[i].x);
		a[i].y=i;
	}
	sort(a+1,a+n+1);
	for(int i=1;i<=n;++i){
		scanf("%d",&b[i].x);
		b[i].y=i;
	}
	sort(b+1,b+n+1);
	for(int i=1;i<=n;++i){
		scanf("%d",&c[i].x);
		c[i].y=i;
	}
	sort(c+1,c+n+1);
	for(int i=1;i<=n;++i){
		p[0][i]=data(a[i].y,b[i].y);
		p[1][i]=data(a[i].y,c[i].y);
		p[2][i]=data(b[i].y,c[i].y);
	}
	for(int i=0;i<3;++i){
		sort(p[i]+1,p[i]+n+1);
		memset(d,0,sizeof(d));
		for(int j=1;j<=n;++j){
			A[i]+=(ll)Query(p[i][j].y);
			Update(p[i][j].y);
		}
	}
	printf("%I64d\n",((ll)n*(ll)(n-1)-((ll)n*(ll)(n-1)/2ll*3ll-A[0]-A[1]-A[2]))/2ll);
	return 0;
}
posted @ 2017-10-20 17:15  AutSky_JadeK  阅读(247)  评论(0编辑  收藏  举报
TVアニメ「Charlotte(シャーロット)」公式サイト TVアニメ「Charlotte(シャーロット)」公式サイト