【JZOJ5105】【GDSOI2017】魔兽争霸 x

xiaoxiao2021-02-28  89

Description

Data Constraint

Solution

我们发现答案最多只有两条直线构成,自己简单画一下就成。 现在问题成了如何求两条直线构成的最优方案。 我们设两条向量分别为(a,b),(c,d),价值分别为e,f,那么设(a,b)的时间为x,我们可以发现在 naxc<mbxd 时, f(x)=ex+fnaxc=(eafc)x+nf/c 这就成了一次函数,求极值应该很容易。

Code

#include<iostream> #include<cmath> #include<cstring> #include<cstdio> #include<algorithm> #define db double using namespace std; const int maxn=1e3+5; const db mo=1e-10; db m[maxn],d[maxn],h[maxn],m1,m2,ans,x,y,z,l,r,mid,ans1[3][2]; int n,i,t,j,k,p; db pan(db x){ db y=(m2-x*m[i])/m[j],z=(m1-x*h[i])/h[j]; return x*d[i]+min(y,z)*d[j]; } void make(db l){ if (pan(l)>ans){ ans=pan(l);ans1[1][0]=i,ans1[1][1]=l; ans1[2][0]=j,ans1[2][1]=min((m2-l*m[i])/m[j],(m1-l*h[i])/h[j]); } } int main(){ freopen("terraria.in","r",stdin);freopen("terraria.out","w",stdout); scanf("%d",&p); while (p){ p--;scanf("%d%lf%lf",&n,&m1,&m2); for (i=1;i<=n;i++)scanf("%lf",&h[i]);//m1 for (i=1;i<=n;i++)scanf("%lf",&m[i]);//m2 for (i=1;i<=n;i++)scanf("%lf",&d[i]); ans=0;memset(ans1,0,sizeof(ans1)); for (i=1;i<=n;i++){ x=min(m2/m[i],m1/h[i]); if (x*d[i]>ans){ ans=x*d[i];ans1[1][0]=i,ans1[1][1]=x; } } for (i=1;i<=n;i++) for (j=i+1;j<=n;j++){ x=m2*h[j]-m1*m[j]; y=m[i]*h[j]-h[i]*m[j];z=min(m2/m[i],m1/h[i]); if (y>0){ l=x/y; r=min(m2/m[i],m1/h[i]); }else{ l=0; r=x/y; } if (l<0) l=0; if (r>z) r=z; if (l<r){ if (d[i]-m[i]*d[j]/m[j]>0) make(r); else make(l); } if (l) r=l,l=0; else l=r,r=min(m2/m[i],m1/h[i]); if (l<0) l=0; if (r>z) r=z; if (l<r){ if (d[i]-h[i]*d[j]/m[j]>0) make(r); else make(l); } } printf("%.10lf\n",ans); for (i=1;i<=n;i++){ if (i!=ans1[1][0] && i!=ans1[2][0]) printf("0.0000000000 "); else if (i==ans1[1][0]) printf("%.10lf ",ans1[1][1]); else if (i==ans1[2][0])printf("%.10lf ",ans1[2][1]); } printf("\n"); } }
转载请注明原文地址: https://www.6miu.com/read-74148.html

最新回复(0)