Algorithm 找到无法赢得比赛的玩家数量?
我们被赋予n名玩家,每个玩家有3个A、B和C值。 如果存在另一名玩家j且该玩家的3个值均为A[j]>A[i]、B[j]>B[i]和C[j]>C[i],则该玩家i无法获胜我们被要求找出无法获胜的玩家数量。 我用蛮力尝试了这个问题,蛮力是对玩家数组的线性搜索。但是它显示出了TLE 对于每个玩家i,我将遍历整个数组,以查找是否存在上述条件成立的任何其他玩家j 代码:Algorithm 找到无法赢得比赛的玩家数量?,algorithm,math,data-structures,fenwick-tree,Algorithm,Math,Data Structures,Fenwick Tree,我们被赋予n名玩家,每个玩家有3个A、B和C值。 如果存在另一名玩家j且该玩家的3个值均为A[j]>A[i]、B[j]>B[i]和C[j]>C[i],则该玩家i无法获胜我们被要求找出无法获胜的玩家数量。 我用蛮力尝试了这个问题,蛮力是对玩家数组的线性搜索。但是它显示出了TLE 对于每个玩家i,我将遍历整个数组,以查找是否存在上述条件成立的任何其他玩家j 代码: int count_players_cannot_win(vector<vector<int>> values)
int count_players_cannot_win(vector<vector<int>> values) {
int c = 0;
int n = values.size();
for(int i = 0; i < n; i++) {
for(int j = 0; j!= i && j < n; j++) {
if(values[i][0] < values[j][0] && values[i][1] < values[j][1] && values[i][2] < values[j][2]) {
c += 1;
break;
}
}
}
return c;
}
n(number of players) <= 10^5
int n;
const int N = 4e5 + 1;
int tree[N];
int get_max(int i, int l, int r, int L) { // range query of max in range v[B+1: n]
if(r < L || n <= l)
return numeric_limits<int>::min();
else if(L <= l)
return tree[i];
int m = (l + r)/2;
return max(get_max(2*i+1, l, m, L), get_max(2*i+2, m+1, r, L));
}
void update(int i, int l, int r, int on, int v) { // point update in tree[on]
if(r < on || on < l)
return;
else if(l == r) {
tree[i] = max(tree[i], v);
return;
}
int m = (l + r)/2;
update(2*i+1, l, m, on, v);
update(2*i+2, m + 1, r, on, v);
tree[i] = max(tree[2*i+1], tree[2*i+2]);
}
bool comp(vector<int> a, vector<int> b) {
return a[0] != b[0] ? a[0] > b[0] : a[1] < b[1];
}
int solve(vector<vector<int>> &v) {
n = v.size();
vector<int> b(n, 0); // reduce the scale of range from [0,10^9] to [0,10^5]
for(int i = 0; i < n; i++) {
b[i] = v[i][1];
}
for(int i = 0; i < n; i++) {
cin >> v[i][2];
}
// sort on 0th col in reverse order
sort(v.begin(), v.end(), comp);
sort(b.begin(), b.end());
int ans = 0;
for(int i = 0; i < n;) {
int j = i;
while(j < n && v[j][0] == v[i][0]) {
int B = v[j][1];
int pos = lower_bound(b.begin(), b.end(), B) - b.begin(); // position of B in b[]
int mx = get_max(0, 0, n - 1, pos + 1);
if(mx > v[j][2])
ans += 1;
j++;
}
while(i < j) {
int B = v[i][1];
int C = v[i][2];
int pos = lower_bound(b.begin(), b.end(), B) - b.begin(); // position of B in b[]
update(0, 0, n - 1, pos, C);
i++;
}
}
return ans;
}
约束条件:
int count_players_cannot_win(vector<vector<int>> values) {
int c = 0;
int n = values.size();
for(int i = 0; i < n; i++) {
for(int j = 0; j!= i && j < n; j++) {
if(values[i][0] < values[j][0] && values[i][1] < values[j][1] && values[i][2] < values[j][2]) {
c += 1;
break;
}
}
}
return c;
}
n(number of players) <= 10^5
int n;
const int N = 4e5 + 1;
int tree[N];
int get_max(int i, int l, int r, int L) { // range query of max in range v[B+1: n]
if(r < L || n <= l)
return numeric_limits<int>::min();
else if(L <= l)
return tree[i];
int m = (l + r)/2;
return max(get_max(2*i+1, l, m, L), get_max(2*i+2, m+1, r, L));
}
void update(int i, int l, int r, int on, int v) { // point update in tree[on]
if(r < on || on < l)
return;
else if(l == r) {
tree[i] = max(tree[i], v);
return;
}
int m = (l + r)/2;
update(2*i+1, l, m, on, v);
update(2*i+2, m + 1, r, on, v);
tree[i] = max(tree[2*i+1], tree[2*i+2]);
}
bool comp(vector<int> a, vector<int> b) {
return a[0] != b[0] ? a[0] > b[0] : a[1] < b[1];
}
int solve(vector<vector<int>> &v) {
n = v.size();
vector<int> b(n, 0); // reduce the scale of range from [0,10^9] to [0,10^5]
for(int i = 0; i < n; i++) {
b[i] = v[i][1];
}
for(int i = 0; i < n; i++) {
cin >> v[i][2];
}
// sort on 0th col in reverse order
sort(v.begin(), v.end(), comp);
sort(b.begin(), b.end());
int ans = 0;
for(int i = 0; i < n;) {
int j = i;
while(j < n && v[j][0] == v[i][0]) {
int B = v[j][1];
int pos = lower_bound(b.begin(), b.end(), B) - b.begin(); // position of B in b[]
int mx = get_max(0, 0, n - 1, pos + 1);
if(mx > v[j][2])
ans += 1;
j++;
}
while(i < j) {
int B = v[i][1];
int C = v[i][2];
int pos = lower_bound(b.begin(), b.end(), B) - b.begin(); // position of B in b[]
update(0, 0, n - 1, pos, C);
i++;
}
}
return ans;
}
n(玩家数量)v[i][2];
}
//按相反顺序在第0列上排序
排序(v.begin(),v.end(),comp);
排序(b.开始(),b.结束());
int ans=0;
对于(int i=0;iv[j][2])
ans+=1;
j++;
}
而(i
此解决方案使用段树,从而解决了中的问题
时间O(n*log(n))和空间O(n)
这种方法在Primusa接受的答案中得到了解释。首先让我们假设我们的输入是以元组列表的形式出现的
T=[(a[0],B[0],C[0]),(a[1],B[1],C[1])…(a[N-1],B[N-1],C[N-1])
我们可以做的第一个观察是,我们可以按T[0]
进行排序(顺序相反)。然后对于每个元组(a,b,c)
,为了确定它是否不能赢,我们询问是否已经看到一个元组(d,e,f)
,这样e>b和&f>c
。我们不需要检查第一个元素,因为我们得到了d>a
*,因为t
是反向排序的
好的,那么现在我们如何检查第二个标准呢
我们可以这样重新构造它:在所有元组(d,e,f)
,我们已经看到了e>b
,那么f
的最大值是多少?如果最大值大于c
,则我们知道此元组无法获胜
为了处理这一部分,我们可以使用具有最大更新和最大范围查询的段树。当我们遇到一个元组(d,e,f)
,我们可以设置树[e]=max(树[e],f)
<代码>树[i]将表示第三个元素,i
是第二个元素
为了回答类似“f的最大值是多少,以致于b的最大值是多少”这样的问题,我们做了max(tree[b+1…])
,以获得一系列可能的第二个元素中最大的第三个元素
因为我们只做后缀查询,所以可以使用修改过的fenwick树,但使用段树更容易解释
这将为我们提供一个O(NlogN)
解决方案,用于排序T
,并使用每个元组的段树执行O(logN)
*注意:这实际上应该是
d>=a
。然而,当我们假设所有事物都是唯一的时,解释算法就更容易了。为了适应第一个元素的重复值,您需要做的唯一修改是在相同值的元组桶中处理查询和更新。这意味着我们将对具有相同第一个元素的所有元组执行检查,只有在这之后,我们才会对所有执行检查的元组更新tree[e]=max(tree[e],f)
。这可以确保当另一个元组查询树时,没有具有相同第一个值的元组已经更新了树。谢谢。我将使用分段树方法用解决方案代码更新这个问题。这是一个出色的解决方案。我一直在考虑分段树的方法,但你们在这里如此轻松地进行了布局,令人印象深刻!你能推荐一些好的资源来学习和练习段树上的问题吗?@Serialazer sure:是一个非常高质量的资源,底部有大量的练习问题,此外,一旦你完成了cp算法,这是一个非常好的实现它们的方法。一组能够获胜的玩家被称为“帕累托前线”或“帕累托前沿”。搜索这些术语将发现算法的其他讨论,例如。