【C++】「一本通 1.2 例 2」Best Cow Fences

【来源】

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 1n105,0Ai2000

【解析】

使用二分查找,寻找是否存在长度不小于为 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;
}

猜你喜欢

转载自blog.csdn.net/Ljnoit/article/details/105572081