题目不难,就是题目不好理解,大致题意为:我过生日,做了N个蛋糕,形状为圆柱形,高度均为1,但是半径不一样。邀请f个朋友过生日。加上自己一共f+1人。要求每个人都有一个pie,并且每个人的pie的体积相同。同时,要求每个人的pie必须要从原有的一块pie上切割(或直接就是原有的一整块pie),题目要 求出 每个人可分得的最大体积的pie.
这个题目的难点就是读题和精度问题。首先要读懂:要求每个人的pie必须要从原有的一块pie上切割(或直接就是原有的一整块pie)。
如果这个读懂了,那么题目就水了。因为很明显的二分查找法求解单调函数。
思路如下:
假设num(V)表示:每个人可得pie体积为V,且此时最多有num(V)个人可分得该体积的pie。那么num(V)显然为单调递减函数(非严格单调函数)
那么接下来要确定的就是V的上下限,不妨设V的下限为所有体积的pie中的最小值,V的上限为所有体积的pie中的最大值,为了程序编写的方便,这里将下限设为0.0,上限设为
2.0*max(v)+1.0。那么我们就是要求得最大的满足条件: num(V)>=f+1的V.
下面是程序: 184K+47MS
#include <stdio.h>
#include <stdlib.h>
#define Max 10010
#define PI 3.14159265359 //PI的精度要经可能的高,经验
#define eps 1e-5 //最小距离
int r[Max];
int Case,n,f;
int main(){
scanf("%d",&Case);
while(Case--){
scanf("%d%d",&n,&f);
int tL=Max,tR=0;
for(int i=1;i<=n;i++){
scanf("%d",&r[i]);
if(r[i]<tL) tL=r[i];
if(r[i]>tR) tR=r[i]; //最大半径
}
double left=0.0,right=2.0*tR*tR*PI+1.0,mid; // 下限为0,上限为2.0*tR*tR*PI+1.0
while(right-left>eps){ // while条件
mid=(right+left)/2.0;
int num=0;
for(int i=1;i<=n;i++){ // 求体积为mid时,可以分得的最多人数
double temp=PI*r[i]*r[i];
while(temp>=mid){ // 连续减法,直至不够减,将剩余的pie丢弃
temp-=mid;
num++; // 每减一次,人数增加一个
}
}
if(num>=f+1) // 若最大人数大于或等于f+1时。则说明足够分,求最大值
left=mid+0.00001;
else // 否则不够分,mid要减小
right=mid-0.00001;
}
printf("%.4lf\n",right); // 小数点后保留4为输出。注意为right,而不为mid或left。
}
return 0;
}