题解 CF535E 【Tavas and Pashmaks】

· · 题解

蒟蒻的第二篇题解

终于做掉了这一题,趁此题暂无题解,赶紧发了庆祝一下qwq
好了,重点说说此题。

首先可得到这个式子:

\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;
}