二分

二分浮点数模板:

const double eps = 1e-7;
double l, r;
while(1+eps< r)
{
    double mid=(l+r)/2;
    if(ok(mid)) l=mid;
    else r=mid;
}

然后两道模板题
HRBUST - 1530
题意:有一个很多个pi,每个pi都是一个圆,然后给你半径,问你能不能平均分给f+1个人,每个人拿到的pi必须是在同一个pi上的。
开始还以为也要分为圆呢,然后不用。。。。所以这道题,直接二分面积就好。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>

using namespace std;
#define eps 1e-4
#define pi acos(-1)
int a[10005];
int n,f;
int ok(double mid)
{
    int ans=0;
    for(int i=0;i<n;i++)
    {
        ans+=(a[i]/mid);
    }
    if(ans>=f+1) return 1;//注意要写= ,不写的话,就相当于到下面那步了,然后范围就会变小,如果mid=8时,ans==f+1,然后mid=6的时候ans=f+1,然后如果更新r的话,然后范围就小啦
    else return 0;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(a,0,sizeof(a));
        scanf("%d %d",&n,&f);
        int MAX=0;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            a[i]=a[i]*a[i];
            if(a[i]>MAX) MAX = a[i];
        }
        double l=0,r=MAX;
        while(l+eps<r)
        {
            double mid = (l+r)/2.0;
            if(ok(mid)) l=mid;
            else r=mid;
        }
       // cout<<r<<endl;
        printf("%.4f\n",r*pi);//这个四舍五入什么的有或没有都没有关系,因为在误差范围内
    }
    return 0;
}

HDU - 4282
题意: X^Z + Y^Z + XYZ = K ,给你一个k问你满足这个表达式的x,y,z有几组。
K (0 < K < 2^31) X < Y, Z > 1
所以 z的范围是【2,31)
x的范围在【1,2^15)
y的范围在【2,2^15)
如果直接枚举的话一定超时,所以我们用把3重循环降为二重循环,枚举x,z,二分找y
然后注意限制条件,要不然会超时

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>

using namespace std;
#define inf 2148473647//如果2147483648超了int 的范围
long long M[40000][40];
void db()
{
    for(int i=1;i<40000;i++)
    {
        M[i][1]=i;
        for(int j=2;j<=31;j++) {if(M[i][j-1]*i<2147483648)  M[i][j]=M[i][j-1]*i;}//
    }
}
int ok(int x,int z,int cnt)
{
    int l=x+1,r=40000;
    while(r>=l)
    {
        int mid=(l+r)/2;
        if(M[mid][z]==0) {r=mid;}//zheli 
        else if(M[mid][z]+(long long)x*mid*z>=cnt) r=mid;
        else  if(M[mid][z]+(long long)x*mid*z==cnt) return 1;//
        else l=mid+1;
    }
    return 0;
}
int main()
{
    long long k;
    db();
    while(scanf("%I64d",&k)!=EOF&&k)
    {
        int ans=0;
        for(int x=1;x<40000&&x<k;x++)
        {
            for(int z=2;z<31;z++)
            {
                if(M[x][z]>=k) break;//
                if(M[x][z]==0) break;//
                long long cnt=k-M[x][z];
                if(cnt-(long long)2*x*z<=0) break;
                if(ok(x,z,cnt)) ans++;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值