牛客 NC13947 Contest(每日一题 6月1日 逆序对)

NC13947 Contest

题目链接:https://ac.nowcoder.com/acm/problem/13947

题目描述

n支队伍一共参加了三场比赛。
一支队伍x认为自己比另一支队伍y强当且仅当x在至少一场比赛中比y的排名高。
求有多少组(x,y),使得x自己觉得比y强,y自己也觉得比x强。
(x, y), (y, x)算一组。

输入描述:

第一行一个整数n,表示队伍数; 接下来n行,每行三个整数a[i], b[i], c[i],分别表示i在第一场、第二场和第三场比赛中的名次;n 最大不超过200000

输出描述:

输出一个整数表示满足条件的(x,y)数;64bit请用lld

输入
4
1 3 1
2 2 4
4 1 2
3 4 3

输出
5

题解

7.18号完成期末考试,这是期末考试结束后第一次做题,在这之前很长时间一直都没有练习,一直在复习准备期末,现在暑假开始了,继续刷题,争取把牛客的每日一题系列都刷完😋。

一共三场比赛a、b、c,我们每次挑选两场比赛比较,这样就有 (a,b)、(a,c)、(b,c) 这三种组合可以比较。一支队伍x认为自己比另一支队伍y强当且仅当x在至少一场比赛中比y的排名高,对 (a,b) 这个组合来看,如果我们把 a 从小到大排序,那么显然答案就是 b 的逆序对的个数(逆序对满足了 a x < a y , b x > b y a_x<a_y,b_x>b_y ax<aybx>by),同理 (a,c)、(b,c) 这两组。如果你仔细观察肯定会发现可能会有重复的,现在我们来找出重复的情况,对任意两个队伍 x、y,如果这两个队伍的三场比赛排名是 a x > a y a_x>a_y ax>ay b x > b y b_x>b_y bx>by c x > c y c_x>c_y cx>cy,得到的结果为0,所以肯定不会出现重复的,这种全大于的情况和全小于的情况是一样的;再看 a x > a y a_x>a_y ax>ay b x > b y b_x>b_y bx>by c x < c y c_x<c_y cx<cy 这种两大一小的情况,会得到 (a,c)、(b,c) 两个符合题意的答案,这里就重复计算了一次,其他剩余的各种情况都是两大一小或两小一大,都同理。所以,我们按照这种逆序对的方法求得的答案,每种对结果有贡献的情况都被重复计算了一次,所以最后的答案要除以二。

Code

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
struct node {
    int a, b, c;
} arr[N];
int c[N];
int n;
ll ans; //答案可能很大,所以要开 ll

int low_bit(int x) {
    return (x & -x);
}

void add(int x, int val) {
    while (x <= n) {
        c[x] += val;
        x += low_bit(x);
    }
}

int query(int x) {
    int res = 0;
    while (x) {
        res += c[x];
        x -= low_bit(x);
    }
    return res;
}

bool cmp1(node A, node B) {
    return A.a > B.a;
}

bool cmp2(node A, node B) {
    return A.b > B.b;
}

int main() {
    std::ios::sync_with_stdio(false), cin.tie(nullptr);
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        cin >> arr[i].a >> arr[i].b >> arr[i].c;
    }
    // (a,b)
    sort(arr + 1, arr + n + 1, cmp1);
    for (int i = 1; i <= n; ++i) {
        ans += query(arr[i].b);
        add(arr[i].b, 1);
    }
    // (a,c)
    memset(c, 0, sizeof(c));
    for (int i = 1; i <= n; ++i) {
        ans += query(arr[i].c);
        add(arr[i].c, 1);
    }
    // (b,c)
    sort(arr + 1, arr + n + 1, cmp2);
    memset(c, 0, sizeof(c));
    for (int i = 1; i <= n; ++i) {
        ans += query(arr[i].c);
        add(arr[i].c, 1);
    }
    cout << ans / 2 << endl;
    return 0;
}
  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值