题目大意:
n n n个运动员,有两段赛道,第 i i i个运动员在第一段赛道跑的速度是 v i 1 v_{i1} vi1,第二段赛道跑的速度是 v i 2 v_{i2} vi2,现在不知道每种赛道的长度,询问有哪些运动员可能最后赢得比赛
解题思路:
-
可以先将运动员速度从小到大排序,第一关键字为第一种速度
-
通过排序,可以先将一些必不可能成为赢家的筛选掉(其两种速度都小于某一个人的两种速度),并且对于两种速度都相同的去重处理
-
对于三个人,中间那个人可能成为赢家的条件是:(已经排序去重)( s s s为第一种速度, t t t为第二种速度,x为第一段长度,y为第二段长度)
x s 2 − x s 1 + y t 2 − y t 1 ≤ 0 , a 1 = 1 s 2 − 1 s 1 < 0 , b 1 = 1 t 2 − 1 t 1 > 0 x s 2 − x s 3 + y t 2 − y t 3 ≤ 0 , a 2 = 1 s 2 − 1 s 3 > 0 , b 1 = 1 t 2 − 1 t 3 < 0 ⇓ b 1 y ≤ − a 1 x ⇒ y ≤ − a 1 b 1 x b 2 y ≤ − a 2 x ⇒ y ≥ − a 2 b 2 x 成 为 赢 家 的 条 件 就 是 要 都 满 足 上 述 条 件 : 则 − a 1 b 1 ≥ − a 2 b 2 ⇒ a 1 b 1 ≤ a 2 b 2 经 过 化 简 就 变 成 了 : s 3 t 1 ( s 1 − s 2 ) ( t 3 − t 2 ) ≥ s 1 t 3 ( s 3 − s 2 ) ( t 1 − t 2 ) \frac{x}{s_2}-\frac{x}{s_1}+\frac{y}{t_2}-\frac{y}{t_1}\le 0,a_1=\frac{1}{s_2}-\frac{1}{s_1} < 0,b_1=\frac{1}{t_2} - \frac{1}{t_1}>0 \\ \frac{x}{s_2}-\frac{x}{s_3}+\frac{y}{t_2}-\frac{y}{t_3}\le 0,a_2=\frac{1}{s_2}-\frac{1}{s_3}>0,b_1=\frac{1}{t_2} - \frac{1}{t_3}<0 \\ \Downarrow \\ b_1y\le-a_1x \Rightarrow y \le -\frac{a_1}{b_1}x \\ b_2y\le-a_2x \Rightarrow y \ge -\frac{a_2}{b_2}x \\ 成为赢家的条件就是要都满足上述条件:则-\frac{a_1}{b_1}\ge -\frac{a_2}{b_2} \Rightarrow \frac{a_1}{b_1}\le\frac{a_2}{b_2} \\ 经过化简就变成了:s_3t_1(s_1-s_2)(t_3-t_2)\ge s_1t_3(s_3-s_2)(t_1-t_2) s2x−s1x+t2y−t1y≤0,a1=s21−s11<0,b1=t21−t11>0s2x−s3x+t2y−t3y≤0,a2=s21−s31>0,b1=t21−t31<0⇓b1y≤−a1x⇒y≤−b1a1xb2y≤−a2x⇒y≥−b2a2x成为赢家的条件就是要都满足上述条件:则−b1a1≥−b2a2⇒b1a1≤b2a2经过化简就变成了:s3t1(s1−s2)(t3−t2)≥s1t3(s3−s2)(t1−t2) -
然后根据这个式子维护一下栈里元素即可
更好的想法:
- 对于式子 A a i + B b i = T \frac{A}{a_i}+\frac{B}{b_i}=T aiA+biB=T,题目就转为对于点 ( 1 a i , 1 b i ) (\frac{1}{a_i},\frac{1}{b_i}) (ai1,bi1),如果存在 ( A , B ) (A,B) (A,B)使得在该点对最小,则输出
- 原式可以看成: A x + B y = T → y = − A B x + T B Ax+By=T\rightarrow y=-\frac{A}{B}x+\frac TB Ax+By=T→y=−BAx+BT
- 由于 ( x , y ) (x,y) (x,y)给定,而斜率恒为负数,所以只要维护一个左下凸包即可,且最终维护凸包的式子就上面的的式子
AC代码:
#include <bits/stdc++.h>
#define ft first
#define sd second
#define pb push_back
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) //不能跟puts混用
#define seteps(N) fixed << setprecision(N)
#define endl "\n"
const int maxn = 2e5 + 10;
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
const ll mod = 1e9 + 7;
int n, m;
struct Speed {
int v1, v2, id;
bool operator < (Speed p) {
if (v1 != p.v1) return v1 < p.v1;
else if (v2 != p.v2) return v2 < p.v2;
else return id < p.id;
}
} sp[maxn], ps[maxn];
int st[maxn], s;
bool vis[maxn];
db slope(int s1, int s2, int t1, int t2) {
return (1.0 / s2 - 1.0 / s1) / (1.0 / t2 - 1.0 / t1);
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) cin >> sp[i].v1 >> sp[i].v2, sp[i].id = i;
sort (sp + 1, sp + n + 1);
m = 1;
ps[1] = sp[1];
for (int i = 2; i <= n; i++) {
while (m >= 1 && ps[m].v2 <= sp[i].v2) m--;
ps[++m] = sp[i];
}
for (int i = 1; i <= m; i++) {
while (s >= 2 && 1ll * ps[i].v1 * ps[st[s - 1]].v2 * (ps[st[s - 1]].v1 - ps[st[s]].v1) * (ps[i].v2 - ps[st[s]].v2) < 1ll * ps[st[s - 1]].v1 * ps[i].v2 * (ps[i].v1 - ps[st[s]].v1) * (ps[st[s - 1]].v2 - ps[st[s]].v2))
s--;
st[++s] = i;
}
for (int i = 1; i <= s; i++) vis[ps[st[i]].id] = true;
for (int i = n; i > 1; i--) {
if (sp[i].v1 == sp[i - 1].v1 && sp[i].v2 == sp[i - 1].v2)
vis[sp[i - 1].id] = vis[sp[i].id];
}
for (int i = 1; i <= n; i++)
if (vis[i])
cout << i << " ";
cout << endl;
return 0;
}