P3291-[SCOI2016]妖怪【凸壳】
正題
題目鏈接:https://www.luogu.com.cn/problem/P3291
題目大意
給出 nnn 個數字對 (atk,dnf)(atk,dnf)(atk,dnf),求一個(a,b)(a,b)(a,b)。
對于每個數字對可以選擇任意一個實數kkk讓其變為(atk+k×a,dnf?k×a)(atk+k\times a,dnf-k\times a)(atk+k×a,dnf?k×a),但是操作完之后兩個數字都非負。記atk/dnf(a,b)atk/dnf(a,b)atk/dnf(a,b)表示在(a,b)(a,b)(a,b)下atk/dnfatk/dnfatk/dnf的最大值。
然后要求最小化max{atki(a,b),dnfi(a,b)}max\{atk_i(a,b),dnf_i(a,b)\}max{atki?(a,b),dnfi?(a,b)}。
1≤n≤106,1≤atk,dnf≤1081\leq n\leq 10^6,1\leq atk,dnf\leq 10^81≤n≤106,1≤atk,dnf≤108
解題思路
首先視(atk,dnf)(atk,dnf)(atk,dnf)為一個點的話,那么對于任意一個(a,b)(a,b)(a,b)答案肯定是在上凸殼上的。
然后考慮實際上我們并不需要用到(a,b)(a,b)(a,b)只需考慮ba\frac{b}{a}ab?的值,定義k=bak=\frac{b}{a}k=ab?
然后就是要求最小化(用aia_iai?代atkiatk_iatki?,did_idi?代dnfidnf_idnfi?)
ai+bi+aik+bi1ka_i+b_i+a_ik+b_i\frac{1}{k}ai?+bi?+ai?k+bi?k1?
考慮這個點在kkk的哪些區間由它取到最大值,對于一個jjj需要滿足
ai+bi+aik+bi1k>aj+bj+ajk+bj1ka_i+b_i+a_ik+b_i\frac{1}{k}>a_j+b_j+a_jk+b_j\frac{1}{k}ai?+bi?+ai?k+bi?k1?>aj?+bj?+aj?k+bj?k1?
化一下
(ai?aj)k2+(ai?aj+bi?bj)k+(bi?bj)>0(a_i-a_j)k^2+(a_i-a_j+b_i-b_j)k+(b_i-b_j)>0(ai??aj?)k2+(ai??aj?+bi??bj?)k+(bi??bj?)>0
然后就是一個二次不等式,并且考慮到jjj只需考慮凸殼上iii左右連接的兩個點,解出來我們可以得到kkk的合法范圍。
然后上面那個是一個對鉤函數,現在只需在這個范圍內求這個對鉤函數的最小值就好了。
時間復雜度O(nlog?n)O(n\log n)O(nlogn)
code
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; const int N=1e6+10; struct node{double x,y; }p[N],s[N]; int n,top;double ans; bool calc(double a,double b,double c,double &l,double &r){double d=b*b-4.0*a*c;if(d<0)return 0;d=sqrt(d);double x0=(-b-d)/(2*a),x1=(-b+d)/(2*a);if(x0>x1)swap(x0,x1);l=x0;r=x1;return 1; } bool cmp(node x,node y) {return (x.x==y.x)?(x.y>y.y):(x.x<y.x);} double solpe(node x,node y) {return (y.y-x.y)/(y.x-x.x);} int main() {scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%lf%lf",&p[i].x,&p[i].y);sort(p+1,p+1+n,cmp);for(int i=1;i<=n;i++){while(top>1&&solpe(s[top-1],s[top])<=solpe(s[top-1],p[i]))top--;s[++top]=p[i];}ans=1e18;for(int i=1;i<=top;i++){double z=sqrt(s[i].y/s[i].x);double l=0,r=1e18,L=1,R=1;bool flag=1;if(i>1)calc(s[i].x-s[i-1].x,s[i].x-s[i-1].x+s[i].y-s[i-1].y,s[i].y-s[i-1].y,L,R);if(i<top)flag&=calc(s[i].x-s[i+1].x,s[i].x-s[i+1].x+s[i].y-s[i+1].y,s[i].y-s[i+1].y,l,r);if(!flag)continue;if(L<l)l=max(R,l);if(R>r)r=min(r,L);if(l>r||r<=0)continue;z=max(z,l);z=min(z,r);if(z>L&&z<R){if(L>=l)ans=min(ans,s[i].x+s[i].y+s[i].x*L+s[i].y/L);if(R<=r)ans=min(ans,s[i].x+s[i].y+s[i].x*R+s[i].y/R);}else ans=min(ans,s[i].x+s[i].y+s[i].x*z+s[i].y/z);}printf("%.4lf\n",ans);return 0; }總結
以上是生活随笔為你收集整理的P3291-[SCOI2016]妖怪【凸壳】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ps6怎么做3d字体(pscs6怎么做3
- 下一篇: ps怎么加参考线(ps怎么加参考线的颜色