【POJ】3122 Pie | 二分

132 阅读2分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

【POJ】3122 Pie | 二分

题目链接

3122 -- Pie (poj.org)

题目

My birthday is coming up and traditionally I'm serving pie. Not just one pie, no, I have a number N of them, of various tastes and of various sizes. F of my friends are coming to my party and each of them gets a piece of pie. This should be one piece of one pie, not several small pieces since that looks messy. This piece can be one whole pie though.

My friends are very annoying and if one of them gets a bigger piece than the others, they start complaining. Therefore all of them should get equally sized (but not necessarily equally shaped) pieces, even if this leads to some pie getting spoiled (which is better than spoiling the party). Of course, I want a piece of pie for myself too, and that piece should also be of the same size.

What is the largest possible piece size all of us can get? All the pies are cylindrical in shape and they all have the same height 1, but the radii of the pies can be different.

题目大意

对于给定的 nn 个半径分别为 rir_i 的圆,要求切出 F+1F+1 个面积相等的块(对形状没有要求,但是每个块应该是完整的),求块的面积最大是多少。

思路

xx 表示切出来的块的面积。

发现我们很难通过已知信息求得 xx,但我们可以很容易的判断 xx 是否是一个合法的答案。同时,若 xx 为最优解,则一定切不出 F+1F+1 个比 xx 面积更大的块;一定能切出 F+1F+1 个比 xx 面积更小的块,满足二分性。

则解法为:二分块的大小,对每个圆能切出的块的数量进行求和,记为 sumsum,比较 sumsumF+1F+1 对二分区间进行转移。

代码

#include <stdio.h>
#include <string.h>
#define max(a,b) (a>b?a:b)
#include <iostream>
#include <iomanip>
using namespace std;

const double pi=31415926.5358979323;
int n,m;
long long s[10001],max_s;
int check(long long x)
{
	if (x==0) return 1;
	int sum=0;
	for (int i=1;i<=n;++i) sum+=s[i]/x;
	if (sum>=m) return 1;
	return 0;
}
int main()
{
	int T;
	for (scanf("%d",&T);T--;)
	{
		scanf("%d%d",&n,&m);
		m++;
		for (int i=1;i<=n;++i) 
			scanf("%lld",&s[i]),
			s[i]=s[i]*s[i]*pi,
			max_s=max(max_s,s[i]);
		long long l=0,r=max_s,mid;
		while (l<r)
		{
			mid=(l+r+1)/2;
			if (check(mid)) l=mid;
			else r=mid-1;
		}
		cout <<fixed<<setprecision(4)<<l/10000000.0<<endl;
	}
        return 0;
}