[二分][前缀和] Jzoj P4809 挖金矿
题解
- 发现直接做好像不可做,答案满足单调性
- 考虑用二分将问题转换为判断性问题,设sum[i][]为第i列的前缀和
- 设当前二分出答案为x,第i列往下挖h[i]层,那么就要满足
- 移项就可以得出
- 那么就枚举每行h[i],然后相加,看是否为正(注意精度问题)
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #define ll long long 5 using namespace std; 6 const ll N=1e5+10; 7 ll n,h,a[N],sum[N]; 8 double l,r,s,mx,mid; 9 int main() 10 { 11 scanf("%lld%lld",&n,&h); 12 for (ll i=1;i<=n;i++) 13 for (ll j=1;j<=h;j++) 14 { 15 scanf("%lld",&a[(i-1)*h+j]); 16 if (a[(i-1)*h+j]>r)r=a[(i-1)*h+j]; 17 if (j!=1) sum[(i-1)*h+j]=sum[(i-1)*h+j-1]+a[(i-1)*h+j]; else sum[(i-1)*h+j]=a[(i-1)*h+j]; 18 } 19 while (l+0.000001<r) 20 { 21 mid=(l+r)/2.0,s=0; 22 for (ll i=1;i<=n;i++) 23 { 24 mx=-2147483647; 25 for (ll j=1;j<=h;j++) mx=max(mx,sum[(i-1)*h+j]-j*mid); 26 s+=mx; 27 } 28 if (s>=0) l=mid; else r=mid; 29 } 30 printf("%.4lf",mid); 31 }