[二分][dp] Jzoj P3454 表白(love)
题解
- 答案:ΣQ1[i]+ΣQ2[i]/ΣC1[i]+ΣC2[i]
- 设当前比例x
- 则有Σ(Q1[i]-C1[i]*x)+Σ(Q2[i]-C2[i]*x)>=0
- 设a[i]为(Q1[i]-C1[i]*x)-(Q2[i]-C2[i]*x)
- 这样的话我们只用判断 最后 两边 取的人 的a 的和>=0
- 考虑二分x,恶心的精度!!!
- 可以用DP来判断二分的合法性
- 设f[i][j]、k[i][j]为前i个人取j个人的a的和
- 先按a数组从大到小排序
- 那么第一队列要选最优的肯定在前面,第二队肯定在后面
- 第一队从前往后取,第二队从后往前取
代码
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 const double e=0.000000001; 8 struct edge{ double x,y,v; }k[510]; 9 int Q1[510],Q2[510],C1[510],C2[510],n1,n2,n; 10 double f[510][510],z[510][510],l,r,mid; 11 bool cmp(edge x,edge y) { return x.v>y.v; } 12 bool pd(double x) 13 { 14 for (int i=1;i<=n;i++) 15 { 16 k[i].x=Q1[i]-C1[i]*x; 17 k[i].y=Q2[i]-C2[i]*x; 18 k[i].v=k[i].x-k[i].y; 19 } 20 sort(k+1,k+n+1,cmp); 21 memset(f,200,sizeof(f)); 22 memset(z,200,sizeof(z)); 23 f[0][0]=0; 24 for (int i=1;i<=n;i++) 25 { 26 f[i][0]=0; 27 for (int j=1;j<=min(n1,i);j++) f[i][j]=max(f[i-1][j],f[i-1][j-1]+k[i].x); 28 } 29 z[0][0]=0; 30 for (int i=n;i>=1;i--) 31 { 32 z[n-i+1][0]=0; 33 for (int j=1;j<=min(n2,n-i+1);j++) z[n-i+1][j]=max(z[n-i][j],z[n-i][j-1]+k[i].y); 34 } 35 for (int i=n1;i<=n-n2;i++) if (f[i][n1]+z[n-i][n2]>=0) return true; 36 return false; 37 } 38 int main() 39 { 40 //freopen("love.in","r",stdin); 41 //freopen("love.out","w",stdout); 42 scanf("%d%d%d",&n,&n1,&n2); 43 for (int i=1;i<=n;i++) scanf("%d%d%d%d",&Q1[i],&C1[i],&Q2[i],&C2[i]); 44 l=0.01; r=2000; 45 while (l+e<r) 46 { 47 mid=(l+r)/2; 48 if (pd(mid)) l=mid; else r=mid-e; 49 } 50 printf("%.6f",l); 51 return 0; 52 }