Description
Data Constraint
Solution
我们发现答案最多只有两条直线构成,自己简单画一下就成。
现在问题成了如何求两条直线构成的最优方案。
我们设两条向量分别为(a,b),(c,d),价值分别为e,f,那么设(a,b)的时间为x,我们可以发现在n−a∗xc<m−b∗xd时,f(x)=ex+f∗n−a∗xc=(e−a∗fc)x+n∗f/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");
}
}