【XJOI】NOIP2016提高组冲剌题1 T1 挖金矿

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Loi_Shirley/article/details/52923822

这里写图片描述

这是个数学题……
设第i列前缀和sum[i],每列选的深度为h[i],每列选的总和就是sum[i][h[i]]
平均值就是:ni=1sum[i][h[i]]ni=1h[i]
显然平均值>0
设平均值为x,移项则有:

i=1n(sum[i][h[i]]h[i]x)0

能让这个式子成立的答案才是正确答案
能成立而且尽可能大的答案才是更优答案
于是就二分啦

//据说这是01分数规划 可是我并不会这个东西
//QAQ我就是当数学题做的呀

代码如下

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int MAXN = 110005;
int h,n,num[MAXN];
long long sum[MAXN];
double l = 0,r,mid,s,mx;//一定注意精度

int main()
{

    scanf("%d %d",&n,&h);
    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= h; j ++)
        {
            int k = (i - 1) * h + j;//二维抽象成一维以后的坐标
            scanf("%d",&num[k]);
            if(num[k] > r)   r = num[k];
            if(j != 1)  sum[k] = sum[k - 1] + num[k];
            else    sum[k] = num[k];
        }
    l = 0;
    while(l + 0.000001 < r)//二分
    {
        mid = (l + r) / 2;
        s = 0;
        for(int i = 1; i <= n; i ++)
        {
            mx = -2147483645;
            for(int j = 1; j <= h; j ++)
                mx = max(mx,sum[(i - 1) * h + j] - j * mid);//尽可能最大
            s += mx;
        }
        if(s >= 0)   l = mid;
        else    r = mid;
    }
    printf("%.4lf",mid);//精度精度精度
    return 0;
}
展开阅读全文

没有更多推荐了,返回首页