题目
题目链接:https://codeforces.com/problemset/problem/535/E
有 (n) 个人,其中第 (i) 个人在一个单位时间内可以跑步 (a_i) 米,游泳 (b_i) 米。
我们称第 (i) 个人可能赢得比赛当且仅当存在正实数 (A,B) 满足 (frac{A}{a_i}+frac{B}{b_i}leq min_{j
eq i}(frac{A}{a_j}+frac{B}{b_j}))。求有多少人可能赢得比赛。
(nleq 2 imes 10^5),(1leq a_i,b_ileq 10^4)。
思路
观察到对于两个人 (i,j),满足 (a_ileq a_j) 且 (b_ileq b_j),那么第 (i) 个人不可能获胜(两个都相等的判一下就好了)。
所以可以按照 (a) 从大到小排序,把不可能获胜的扔掉后,(b) 一定严格递增,并且点数最多只有 (10^4) 个。
考虑第 (i) 个人获胜的前提:假设我们确定了第一个项目距离为 (1),那么为了比前 (i-1) 个人时间更短((a) 已经降序了),可以算出第二个项目至少需要 (maxleft(frac{frac{1}{a_i}-frac{1}{a_j}}{frac{1}{b_j}-frac{1}{b_i}}
ight)) 米。
同理可以计算出如果第二个项目为 (1) 米,那么为了比后面的快,第一个项目所需要的距离。设这两个距离分别为 (s_1,s_2)。
那么第 (i) 个人可能获胜当且仅当 (s_1 imes s_2leq 1)。
直接 (O(n^2)) 跑就行了。
代码
#include <bits/stdc++.h>
#define mp make_pair
using namespace std;
const int N=200010;
const double eps=1e-8;
int n,m;
map<pair<int,int>,bool> v;
struct node
{
int a,b;
}a[N],b[N];
bool cmp(node x,node y)
{
if (x.a!=y.a) return x.a>y.a;
return x.b>y.b;
}
int main()
{
scanf("%d",&m);
for (int i=1;i<=m;i++)
{
scanf("%d%d",&a[i].a,&a[i].b);
b[i]=a[i];
}
sort(a+1,a+1+m,cmp);
n=1;
for (int i=2;i<=m;i++)
if (a[i].a<a[n].a && a[i].b>a[n].b) a[++n]=a[i];
for (int i=1;i<=n;i++)
{
if (i==1 || i==n) { v[mp(a[i].a,a[i].b)]=1; continue; }
double mx1=0,mx2=0;
for (int j=1;j<i;j++)
mx1=max(mx1,(1.0/a[i].a-1.0/a[j].a)/(1.0/a[j].b-1.0/a[i].b));
for (int j=n;j>i;j--)
mx2=max(mx2,(1.0/a[i].b-1.0/a[j].b)/(1.0/a[j].a-1.0/a[i].a));
if (mx1*mx2<1.0+eps) v[mp(a[i].a,a[i].b)]=1;
}
for (int i=1;i<=m;i++)
if (v[mp(b[i].a,b[i].b)]==1) cout<<i<<" ";
return 0;
}