【来源】
USACO 2003 Mar. Green
一本通题库-1434
LibreOJ-10012
POJ-2018
OpenJ_Bailian-2018
SCU-2153
vjudge
【题目描述】
Farmer John’s farm consists of a long row of N (1 <= N <= 100,000)fields. Each field contains a certain number of cows, 1 <= ncows <= 2000.
FJ wants to build a fence around a contiguous group of these fields in order to maximize the average number of cows per field within that block. The block must contain at least F (1 <= F <= N) fields, where F given as input.
Calculate the fence placement that maximizes the average, given the constraint.
给定一个长度为 n 的非负整数序列 A ,求一个平均数最大的,长度不小于 L 的子段。
【输入格式】
-
Line 1: Two space-separated integers, N and F.
-
Lines 2…N+1: Each line contains a single integer, the number of cows in a field. Line 2 gives the number of cows in field 1,line 3 gives the number in field 2, and so on.
第一行用空格分隔的两个整数 n 和 L;
第二行为 n 个用空格隔开的非负整数,表示 Ai。
【输出格式】
- Line 1: A single integer that is 1000 times the maximal average.Do not perform rounding, just print the integer that is 1000*ncows/nfields.
输出一个整数,表示这个平均数的 1000 倍。不用四舍五入,直接输出。
【样例输入】
10 6
6
4
2
10
3
8
5
9
4
1
【样例输出】
6500
【数据范围】
1 ≤ n ≤ 1 0 5 , 0 ≤ A i ≤ 2000 1≤n≤10^5,0≤A_i≤2000 1≤n≤105,0≤Ai≤2000。
【解析】
使用二分查找,寻找是否存在长度不小于为 L 的子段的平均数大于二分答案。用二分枚举平均值 avg,数组里每个值都减去 avg,看是否有连续的超过 L 长度的区间使得这段区间的总和大于等于 0,如果能找到,那么说明这个平均值可以达到。
细节:cin有可能超时、要用long long、double。
可以有好几种方法来实现。
【代码1】
#pragma GCC optimize(3,"Ofast","inline")
#pragma G++ optimize(3,"Ofast","inline")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define RI register int
#define re(i,a,b) for(RI i=a; i<=b; i++)
#define ms(i,a) memset(a,i,sizeof(a))
#define MAX(a,b) (((a)>(b)) ? (a):(b))
#define MIN(a,b) (((a)<(b)) ? (a):(b))
using namespace std;
typedef long long LL;
const int N=1e5+5;
const int inf=2e9;
int n,m;
int a[N];
long long sum[N];
inline int chk(int avg,int n,int m) {
for(int i=1; i<=n; i++) sum[i]=sum[i-1]+a[i]-avg;
long long res=0;
for(int i=m; i<=n; i++) {
if(sum[i-m]<res) res=sum[i-m];
if(sum[i]>=res) return 1;
}
return 0;
}
int main() {
scanf("%d%d",&n,&m);
int l=inf,r=0;
for(int i=1; i<=n; i++) {
scanf("%d",&a[i]);
a[i]=a[i]*1000;
l=MIN(l,a[i]),r=MAX(r,a[i]);
}
int ans,mid;
while(l<=r) {
mid=(l+r)>>1;
if(chk(mid,n,m)) ans=mid,l=mid+1;
else r=mid-1;
}
printf("%d\n",ans);
return 0;
}
【代码2】
#pragma GCC optimize(3,"Ofast","inline")
#pragma G++ optimize(3,"Ofast","inline")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define RI register int
#define re(i,a,b) for(RI i=a; i<=b; i++)
#define ms(i,a) memset(a,i,sizeof(a))
#define MAX(a,b) (((a)>(b)) ? (a):(b))
#define MIN(a,b) (((a)<(b)) ? (a):(b))
using namespace std;
typedef long long LL;
const int N=1e5+5;
const int inf=2e9;
int n,m;
double a[N],b[N],sum[N];
int main() {
scanf("%d%d",&n,&m);
double l=inf,r=0;
for(int i=1; i<=n; i++) {
scanf("%lf",&a[i]);
l=MIN(l,a[i]),r=MAX(r,a[i]);
}
double eps=1e-6;
while(r-l>eps) {
double mid=(l+r)/2.0;
for(int i=1; i<=n; i++) {
b[i]=a[i]-mid;
sum[i]=sum[i-1]+b[i];
}
double ans=-inf,mi=inf;
for(int i=m; i<=n; i++) {
mi=MIN(mi,sum[i-m]);
ans=MAX(ans,sum[i]-mi);
}
if(ans>=0) l=mid;
else r=mid;
}
printf("%d\n",(int)(r*1000));
return 0;
}
【代码3】
这段代码更加精炼,有点不想二分,但方法是一样的。把mid和a[]省了。
#pragma GCC optimize(3,"Ofast","inline")
#pragma G++ optimize(3,"Ofast","inline")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define RI register int
#define re(i,a,b) for(RI i=a; i<=b; i++)
#define ms(i,a) memset(a,i,sizeof(a))
#define MAX(a,b) (((a)>(b)) ? (a):(b))
#define MIN(a,b) (((a)<(b)) ? (a):(b))
using namespace std;
typedef long long LL;
const int N=1e5+5;
const int inf=2e9;
int n,m;
int sum[N];
int main() {
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++) {
int x;
scanf("%d",&x);
sum[i]=sum[i-1]+x;
}
double ans=-inf;
int l=1,r=m;
while(r<=n) {
if(sum[r-m]-sum[l-1]<=ans*(r-l-m+1))
l=r-m+1;
ans=MAX(ans,(sum[r]-sum[l-1])*1.0/(r-l+1));
r++;
}
printf("%d\n",(int)(ans*1000));
return 0;
}