给出三个1~n的排列a,b,c
求
n<=2e6
就是求长方体内的点的个数
很容易想到的是排序,然后扫描,用二维数据结构或者分治+数据结构维护
这样的复杂度是 O(Nlog2N) 的
发掘此题的特殊性,a,b,c都是排列
那么考虑将三维数点转化成二维数点
可以容斥
对于下标对(x,y),我们先不考虑顺序,那么a,b,c中要么全部满足,要么满足两个
如果将这两个排列两两放在一起数,那么就可以容斥了
即设 Pa,b=∑i,j[ai<aj][bi<bj]
考虑 Pa,b+Pb,c+Pa,c
这三种加起来,那么只满足两个的情况算了一遍,全部满足的情况算了3遍
即设
那么S+S1就是全部的情况, 3∗S+S1=Pa,b+Pb,c+Pa,c
成功转化为二维数点问题,排序+树状数组解决
#include
#include
#include
#include
#include
#include
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define N 2000005
#define LL long long
using namespace std;
int a[N],b[N],c[N],n,s[N];
LL seed,dl;
LL rnd()
{
return seed=((seed*(LL)19260817)^(LL)233333)&dl;
}
struct node
{
int x,y;
friend bool operator <(node x,node y)
{
return x.xvoid gen(int *a)
{
fo(i,1,n) a[i]=i;
fo(i,1,n) swap(a[i],a[rnd()%i+1]);
}
int lowbit(int k)
{
return k&(-k);
}
void put(int k)
{
while(k<=n) s[k]++,k+=lowbit(k);
}
LL fd(int k)
{
LL s1=0;
while(k) s1+=s[k],k-=lowbit(k);
return s1;
}
LL get(int *a,int *b)
{
fo(i,1,n) a1[i].x=a[i],a1[i].y=b[i];
sort(a1+1,a1+n+1);
memset(s,0,sizeof(s));
LL ans=0;
fo(i,1,n) ans+=fd(a1[i].y-1),put(a1[i].y);
return ans;
}
int main()
{
freopen("dalao.in","r",stdin);
freopen("dalao.out","w",stdout);
dl=(1<<24)-1;
cin>>n;
scanf("%lld",&seed),gen(a);
scanf("%lld",&seed),gen(b);
scanf("%lld",&seed),gen(c);
LL ans=get(a,b)+get(b,c)+get(c,a)-(LL)n*(LL)(n-1)/2;
printf("%lld\n",ans/2);
}