CF535E 计算几何

题目大意:

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) s2xs1x+t2yt1y0,a1=s21s11<0,b1=t21t11>0s2xs3x+t2yt3y0,a2=s21s31>0,b1=t21t31<0b1ya1xyb1a1xb2ya2xyb2a2xb1a1b2a2b1a1b2a2s3t1(s1s2)(t3t2)s1t3(s3s2)(t1t2)

  • 然后根据这个式子维护一下栈里元素即可

更好的想法:

  • 对于式子 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=Ty=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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值