4809. 【NOIP2016提高A组五校联考1】挖金矿

Description

Input

Output

Sample Input

4 3
4 3 3
5 1 6
2 6 1
3 2 9

Sample Output

4.4286

Data Constraint

Hint

Source / Author: 学军中学 gold

题解:

二分。

二分期望平均数mid,如果这个mid是可能的,则

\tfrac{\sum_{i=1}^{tot}a[i] }{tot} >=mid

化简得 sum(a[i] - mid)>=0

所以,对于任意一个mid,只需要把所有矿的价值减去mid,然后每一列做一个前缀和。

对于每一列的前缀和数组,取出一个最大值加到sum中(sum初始值为0),最后看sum是否大于等于0即可。

#include<bits/stdc++.h>
#define N 100010
#define inf 2147483647
#define open(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout)
#define mem(a,b) memset(a,b,sizeof(a))
#define mcy(a,b) memcpy(a,b,sizeof(a))
using namespace std;

struct point
{
	double next,val,pre;
}a[N];
int i,j,tot,n,h;
double maxx,root[N];
double l,r,mid,ans;

void make()
{
	for(i=1;i<=n;i++)
	{
		int p=root[i],last=0;
		while(p)
		{
			a[p].pre = a[p].val - mid + a[last].pre;	
			last=p;
			p=a[p].next;
		}
	}
}

double gain()
{
	double sum=0;
	for(i=1;i<=n;i++)
	{
		int p=root[i],last=0;
		double tmp=-inf;
		while(p)
		{
			tmp = max(tmp,a[p].pre);
			p=a[p].next;
		}
		sum+=tmp;
	}
	return sum;
}

int main()
{
	open("goldmine");
	scanf("%d%d",&n,&h);
	for(i=1;i<=n;i++) 
	{
		for(j=1;j<=h;j++) 
		{
			++tot;
			scanf("%lf",&a[tot].val); maxx = max(maxx,a[tot].val);
			if(j!=1) a[tot-1] . next = tot; else root[i] = tot;
		}
	}
	
	l=1.00;
	r=maxx;
	while((r-l)>0.00001)
	{
		mid = (l+r) / 2.00;
		make();
		if(gain() >=0.00)
		{
			ans = mid;
			l = mid;
		} else r  = mid;
	}
	
	printf("%.4lf",ans);
	return 0;
}

O(n log  n)

猜你喜欢

转载自blog.csdn.net/Com_man_der/article/details/94570791
今日推荐