1. 程式人生 > 實用技巧 >【LZU第四屆程式設計大賽】終極較量

【LZU第四屆程式設計大賽】終極較量

Description

比賽很快就開始了,所有參賽的選手將在這裡展開一場全面的終極較量。

每一位選手都有三個屬性 \(A\)\(B\)\(C\),每個屬性都是一個正整數,

如果一個選手 \(X\) 有一個屬性的值大於另一個選手 \(Y\) 對應的屬性值,則認為 \(X\) 可以擊敗 \(Y\)

如果 \(X\) 能夠擊敗 \(Y\)\(Y\) 能夠擊敗 \(Z\),則認為 \(X\) 也能擊敗 \(Z\)

在一個選手能夠擊敗的人中,每個人統計且僅統計一次,請你幫 \(GJX\) 算一算,他能夠擊敗多少角色。

特別的,選手自己不能擊敗自己,即自己不會出現在自己擊敗的計數中。

Input

第一行,一個整數 \(n \ (1 \leq n \leq 2 \times 10^5)\),代表該遊戲中的所有玩家數;

第二行,\(3\) 個正整數(不超過 \(int\)),分別代表 \(GJX\) 的三個屬性值;

接下來的 \(n - 1\) 行,每行 \(3\) 個數,代表除了 \(GJX\) 以外的選手的三個屬性的值;

資料保證不會出現兩位選手的所有屬性值相同。

Output

一行,一個整數,代表 \(GJX\) 最多可以擊敗多少選手(不包括 \(GJX\) 自己)。

Sample Input 1

3
10 1 3
9 5 7
3 8 2

Sample Output 1

2

題解

考慮這樣的集合,集合之中的任意一人不會被集合之外的人打敗,

在保證 \(GJX\) 不在這樣的集合之中的前提下,最大化這個集合就能解決問題。

按照三個屬性值分別排序,然後從 \(1\)\(n\) 依次考慮上述集合的大小,

把當前考慮到的大小,在按三個屬性值排序的陣列中涉及到的人統計下來,

如果涉及人數和當前考慮的大小一致,說明找到了一個這樣的集合;

需要注意的是,如果這期間在任意陣列遇到 \(GJX\) 都要停止。

AC程式碼

點選展開
#include <cstdio>
#include <algorithm>

using namespace std;

inline int read() {
    int num = 0;
    char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9')
        num = num * 10 + c - '0', c = getchar();
    return num;
}

const int MAXN = 2e5 + 5;

struct Person {
    int id, value;

    bool operator < (const Person &rhs) const {
        return value > rhs.value;
    }
} a[MAXN], b[MAXN], c[MAXN];

int vis[MAXN];

int main() {
    int n = read();
    for (int i = 1; i <= n; ++i) {
        a[i].id = i, a[i].value = read();
        b[i].id = i, b[i].value = read();
        c[i].id = i, c[i].value = read();
    }
    sort(a + 1, a + n + 1);
    sort(b + 1, b + n + 1);
    sort(c + 1, c + n + 1);
    int ans = n - 1, num = 0, cnt = 0;
    for (int i = 1; i <= n; ++i) {
        if (a[i].id == 1 || b[i].id == 1 || c[i].id == 1) break;
        if (!vis[a[i].id]) ++cnt, vis[a[i].id] = 1;
        if (!vis[b[i].id]) ++cnt, vis[b[i].id] = 1;
        if (!vis[c[i].id]) ++cnt, vis[c[i].id] = 1;
        if (cnt == i - num) num += cnt, cnt = 0;
    }
    printf("%d", ans - num);
    return 0;
}