【XSY2714】大佬的难题 数学 树状数组

题目描述

  给你三个排列(A,B,C),求

[sum_{1leq x,yleq n}[a_x<a_y][b_x<b_y][c_x<c_y] ]

  (nleq 2 imes {10}^6)

题解

  就是一个三位偏序。用CDQ分治可以做到(O(nlog^2 n))常熟小一点可以卡过。我在UOJ上面能跑过去。

  这道题只有一个特殊性质:(A,B,C)都是排列。

  我们记

[egin{align} K_{x,y}&=[a_x<a_y]+[b_x<b_y]+[c_x<c_y]\ S_{x,y}&=max(K_{x,y},K_{y,x})\ A&=sum_{1leq xleq yleq n}[S_{x,y}=3]\ B&=sum_{1leq xleq yleq n}[S_{x,y}=2]\ P_{a,b}&=sum_{1leq x,yleq n}[a_x<a_y][b_x<b_y]\ P_{a,c}&=sum_{1leq x,yleq n}[a_x<a_y][c_x<c_y]\ P_{b,c}&=sum_{1leq x,yleq n}[b_x<b_y][c_x<c_y]\ end{align} ]

  那么我们要求的答案就是(A)了。

  容易发现

[egin{align} A+B&=inom{n}{2}\ 3A+B&=P_{a,b}+P_{a,c}+P_{b,c} end{align} ]

  原问题转化为二位偏序。

  用树状数组即可解决。

  时间复杂度:(O(nlog n))

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<utility>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
ll seed;
ll rd()
{
	return seed=((seed*19260817)^233333)&((1<<24)-1);
}
int n;
void gen(int *a)
{
	int i;
	for(i=1;i<=n;i++)
		a[i]=i;
	for(i=1;i<=n;i++)
		swap(a[i],a[rd()%i+1]);
}
int a1[2000010];
int a2[2000010];
int a3[2000010];
int a[2000010];
int c[2000010];
void add(int x)
{
	for(;x<=n;x+=x&-x)
		c[x]++;
}
int sum(int x)
{
	int s=0;
	for(;x;x-=x&-x)
		s+=c[x];
	return s;
}
ll gao(int *a1,int *a2)
{
	memset(c,0,sizeof c);
	int i;
	for(i=1;i<=n;i++)
		a[a1[i]]=a2[i];
	ll s=0;
	for(i=1;i<=n;i++)
	{
		s+=sum(a[i]);
		add(a[i]);
	}
	return s;
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	scanf("%d",&n);
	scanf("%lld",&seed);
	gen(a1);
	scanf("%lld",&seed);
	gen(a2);
	scanf("%lld",&seed);
	gen(a3);
	ll ans=0;
	ans+=gao(a1,a2);
	ans+=gao(a1,a3);
	ans+=gao(a2,a3);
	ans-=ll(n-1)*n/2;
	ans/=2;
	printf("%lld
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/ywwyww/p/8513559.html