【POJ2018】【实数域上的二分】【dp】
传送门:http://poj.org/problem?id=2018;
大概题意是求一个正整数数列 A 的平均数最大 长度不小于 L 的子段
我们可以二分答案 判定是否有一个长度不小于L的子段 平均数不小于二分值
我们把数列数减去二分的答案 则判断是否一个长度不小于L的子段 和大于0
众所周知我们可以用两个前缀和的值相减来表示
我们只用对于每个i记录在i-L前最小的sum就可以了
贴代码(同时注意一些实数域二分的技巧就好)
#include<iostream> #include<cstdio> using namespace std; long long n,L; double a[1000001],b[1000001],sum[1000001]; int main() { scanf("%lld%lld",&n,&L); for(long long i = 1;i <= n;i++) scanf("%lf",&a[i]); double eps = 1e-5; double l = -1e6,r = 1e6; while (r - l > eps) { double mid = (l + r) / 2; for(long long i = 1; i <= n; i++) b[i] = a[i] - mid; for(long long i = 1; i <= n; i++) sum[i] = sum[i - 1] + b[i]; double ans = -1e10; double min_val = 1e10; for(long long i = L; i <= n ; i++) { min_val = min(min_val, sum[i - L]); ans = max(ans, sum[i] - min_val); } if(ans >= 0) l = mid; else r = mid; } cout << int (r * 1000) << endl; }