题解 CF535E 【Tavas and Pashmaks】

首先可得到这个式子:

(frac{A}{a_{i}}+frac{B}{b_{i}}=T​)

其中 (T​) 表示时间,这个式子应该不难理解,题目就转换成了对于一对 ((a_{i}​) , (b_{i})​) ,如果存在一对 ((A,B)​) 使得时间 (T​)((a_{i}​) , (b_{i})​) 上最小,就输出。
接下来是做法:
考虑把 ((frac{1}{a_{i}}​) , (frac{1}{b_{i}})​) 看做平面上的点,原式变成 (Ax+By=T​) ,这就是你们喜欢的一次函数啦。继续把原式变得更通俗

(y=-frac{A}{B}x+frac{T}{B}​)

由于点 ((x,y)​) 是给定的,假设你已经确定直线的斜率,也就是 (-frac{A}{B}​) ,你就可以算出时间 (T​) ,进而轻松地确定哪对点是答案。
那么,怎么确定斜率呢?我们可以通过画图发现,是答案的点一定在平面图的左下凸包上,如果明白凸包的思想,
那么问题就很简单了,至于没学过凸包的同学,可以参考yyb的博客这篇博客没学凸包还想做此题?),蒟蒻我就不多说了qwq
如果看懂了上述内容但不懂凸包过程,请转

上代码:

#include<bits/stdc++.h>
#define ll long long
#define ld long double 
using namespace std;
inline ll read(){
    ll f=1,w=0;char x=0;
    while(!(x>='0'&&x<='9'))
    {
        x=getchar();
        if(x=='-') f=-1;
    }
    while(x>='0'&&x<='9')
    {
        w=(w<<3)+(w<<1)+(x^48);
        x=getchar();
    }
    return f*w;
}//习惯性的快读
struct people{
    ll a,b,id;
}p[300010];
ll n,s[300010],t;
bool v[300010],ans[300010];
bool cmp(people a,people b){
    if(a.a==b.a) return a.b>b.b;
    return a.a>b.a;
}//凸包排序
ld check(people a,people b){
    return (ld)a.a*b.a*(b.b-a.b)/(b.a-a.a)/b.b/a.b;
}//斜率的计算
int main(){
    n=read();
    for(int i=1;i<=n;i++) p[i].a=read(),p[i].b=read(),p[i].id=i;
    sort(p+1,p+n+1,cmp);
    s[1]=1,t=1;
    ll maxb=p[1].b;
    for(int i=2;i<=n;i++)
        if(p[i].b<=maxb) v[i]=1;
        else maxb=p[i].b;
    //去重和排除能一眼看出非答案的点,譬如a和b都比另一个点小
    for(int i=2;i<=n;i++)
    {
        if(v[i]||check(p[i],p[s[t]])>0) continue;//斜率大于0排除
        while(t>1&&check(p[i],p[s[t]])<check(p[s[t-1]],p[s[t]]))
            t--;
        s[++t]=i;
    }//单调栈维护的类似于凸包的过程
    for(int i=1;i<=t;i++)
    {
        ans[p[s[i]].id]=1;
        for(int j=s[i]+1;j<=n&&p[s[i]].a==p[j].a&&p[s[i]].b==p[j].b;j++)
            ans[p[j].id]=1;
    }//还原位置相同的点
    for(int i=1;i<=n;i++)
        if(ans[i]) cout<<i<<" ";
    return 0;
}
原文地址:https://www.cnblogs.com/ajy-shi-cj-zui-cai/p/10386720.html