【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;
}