2018北大暑校acm算法训练课程 派 二分

总时间限制: 1000ms 内存限制: 65536kB
描述
我的生日要到了!根据习俗,我需要将一些派分给大家。我有N个不同口味、不同大小的派。有F个朋友会来参加我的派对,每个人会拿到一块派(必须一个派的一块,不能由几个派的小块拼成;可以是一整个派)。

我的朋友们都特别小气,如果有人拿到更大的一块,就会开始抱怨。因此所有人拿到的派是同样大小的(但不需要是同样形状的),虽然这样有些派会被浪费,但总比搞砸整个派对好。当然,我也要给自己留一块,而这一块也要和其他人的同样大小。

请问我们每个人拿到的派最大是多少?每个派都是一个高为1,半径不等的圆柱体。

输入
第一行包含两个正整数N和F,1 ≤ N, F ≤ 10 000,表示派的数量和朋友的数量。
第二行包含N个1到10000之间的整数,表示每个派的半径。
输出
输出每个人能得到的最大的派的体积,精确到小数点后三位。
样例输入
3 3
4 3 3
样例输出
25.133

题目分析:首先第二段最后说道要给自己留一块,这样吧的话总共要分的块数就是F+1.
其次每一个派的大小不一(注意题目中说分的派必须是整块,但对形状没有要求).这样的话我们可以想像一下,小的块可以切很多份,但是大的块却不一定能够切下,满足二分算法的要求.
另外如果不使用三角函数算pi的话,请将pi的小数定义的位数多一些,不然就会wa(精度不够)
故我们设下界为0,上界为最大的派,不断二分求解答案
二分函数:

#define _rep(i,a,b) for( int i=(a); i<=(b); ++i)
bool C(double now){
    int cal=0;
    _rep(i,0,n){
        int tem=a[i]/now;
        cal+=tem;
    }
    return cal>=m ? true:false;
}

完整代码如下:

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int MAX_N=100000;
const int INF = 0x3f3f3f3f;
#define eps 1e-7
//#define Kongxiangzhouye
#define _for(i,a,b) for( int i=(a); i<(b); ++i)
#define _rep(i,a,b) for( int i=(a); i<=(b); ++i)
int readint(){int x;cin>>x;return x;}
double a[10101];
const double PI=3.141592653589;
double EPS=1e-6;
int n,m;
bool C(double now){
    int cal=0;
    _rep(i,0,n){
        int tem=a[i]/now;
        cal+=tem;
    }
    return cal>=m ? true:false;
}
int main(){
    ios::sync_with_stdio(false);
    #ifdef Kongxiangzhouye
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
    while(scanf("%d%d",&n,&m)!=EOF){
        m++;
        double L=0,R=0;
        _for(i,0,n){
            scanf("%lf",&a[i]);
            a[i]=PI*a[i]*a[i];
            R=max(R,a[i]);
        }
    //  cout<<"success"<<endl;
        while(R-L>=EPS){//(r-l可以保证不会出现越界)
            double mid=L+(R-L)/2;
    //      cout<<mid<<endl;
            if(C(mid))
                L=mid;
            else
                R=mid;
        }
        printf("%.3lf\n",L);
    }

    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值