Sample Input
Sample Input1:
4
201334450
1474105774
350932494
Sample Input2:
97670
1734691087
759688311
1371087904
Sample Output
Sample Output1:
4
Sample Output2:
1240045279
样例说明:
样例中 a = {2,3,4,1},b = {2,3,4,1},c = {3,1,4,2}
满足条件的 (x,y) = {(1,3),(2,3),(4,1),(4,3)}
Data Constraint
对于 10% 的数据, n ≤ 5000.
对于 20% 的数据, n ≤ 10 ^ 5 .
对于另外 20% 的数据, n ≤ 10 ^5 , 空间限制 64MB.
对于另外 20% 的数据, n ≤ 5 × 10 ^5 .
对于 100% 的数据, n ≤ 2 × 10 ^6 , seed ≤ 2 × 10 ^9 , 若无特殊说明空间限制256MB。
题解
对于前面的n≤5000,直接可以暴力。
先对题目的式子进行一下改变,
|ax<ay|+|bx<by|+|cx<cy|
如果对于一对(x,y)或者(y,x),它们的最大值要么是2要么是3,
因此可以想到容斥原理。
设A=
|ax<ay|+|bx<by|+|cx<cy|=3
的数量
B=
|ax<ay|+|bx<by|+|cx<cy|=2
的数量
可以得到
A+B=n*(n-1)/2
3A+B=(a,b)+(b,c)+(a,c)
(a,b)就表示a,b两个序列满足
|ax<ay|+|bx<by|
的对数。
现在问题就转化成二维的,
很好解决。
code
#include<queue>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#define ll long long
#define N 2000003
#define db double
#define P putchar
#define G getchar
#define mo 998244353
#define inf 10000000
using namespace std;
char ch;
void read(int &n)
{
n=0;
ch=G();
while((ch<'0' || ch>'9') && ch!='-')ch=G();
ll w=1;
if(ch=='-')w=-1,ch=G();
while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
n*=w;
}
ll max(ll a,ll b){return a>b?a:b;}
ll min(ll a,ll b){return a<b?a:b;}
ll abs(ll x){return x<0?-x:x;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}
struct node
{
int a,b;
}t[N];
ll seed,ans,z;
int a[N],b[N],c[N],n,s[N];
ll Rand()
{
return seed=((seed*19260817)^233333)&(z-1);
}
void gen(int *a)
{
for(int i=1;i<=n;i++)
a[i]=i;
for(int i=1;i<=n;i++)
swap(a[i],a[Rand()%i+1]);
}
bool cmp(node x,node y)
{
return x.a<y.a;
}
void ins(int x)
{
for(int i=x;i<=n;i=i+(i&(-i)))
s[i]++;
}
ll find(int x)
{
ll sum=0;
for(int i=x;i;i=i-(i&(-i)))
sum+=s[i];
return sum;
}
ll work(int *a,int *b)
{
ll sum=0;
memset(s,0,sizeof(s));
for(int i=1;i<=n;i++)
t[i].a=a[i],t[i].b=b[i];
sort(t+1,t+1+n,cmp);
for(int i=1;i<=n;i++)
sum+=find(t[i].b),ins(t[i].b);
return sum;
}
int main()
{
z=1<<24;
freopen("dalao.in","r",stdin);
freopen("dalao.out","w",stdout);
scanf("%d",&n);
scanf("%lld",&seed);gen(a);
scanf("%lld",&seed);gen(b);
scanf("%lld",&seed);gen(c);
ans=work(a,b)+work(b,c)+work(a,c);
ans-=(ll)n*(n-1)/2;
ans>>=1;
printf("%lld\n",ans);
}