【CF535E】Tavas and Pashmaks
题目
题目链接: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\neq i}(\frac{A}{a_j}+\frac{B}{b_j})\)。求有多少人可能赢得比赛。
\(n\leq 2\times 10^5\),\(1\leq a_i,b_i\leq 10^4\)。
思路
观察到对于两个人 \(i,j\),满足 \(a_i\leq a_j\) 且 \(b_i\leq b_j\),那么第 \(i\) 个人不可能获胜(两个都相等的判一下就好了)。
所以可以按照 \(a\) 从大到小排序,把不可能获胜的扔掉后,\(b\) 一定严格递增,并且点数最多只有 \(10^4\) 个。
考虑第 \(i\) 个人获胜的前提:假设我们确定了第一个项目距离为 \(1\),那么为了比前 \(i-1\) 个人时间更短(\(a\) 已经降序了),可以算出第二个项目至少需要 \(\max\left(\frac{\frac{1}{a_i}-\frac{1}{a_j}}{\frac{1}{b_j}-\frac{1}{b_i}}\right)\) 米。
同理可以计算出如果第二个项目为 \(1\) 米,那么为了比后面的快,第一个项目所需要的距离。设这两个距离分别为 \(s_1,s_2\)。
那么第 \(i\) 个人可能获胜当且仅当 \(s_1\times s_2\leq 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;
}