题目描述
给你三个排列(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;
}