1. 程式人生 > >題解 CF535E 【Tavas and Pashmaks】

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