题解 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; }
 

猜你喜欢

转载自www.cnblogs.com/ajy-shi-cj-zui-cai/p/9826898.html