JZOJ5498. 【清华集训2017模拟12.10】大佬的难题

这里写图片描述
这里写图片描述

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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值