缺失的数据范围 (优雅的二分,特别注意精度问题)

著名出题人小Q出过非常多的题目,在这个漫长的过程中他发现,确定题目的数据范围是非常痛苦的一件事。

每当思考完一道题目的时间效率,小Q就需要结合时限以及评测机配置来设置合理的数据范围。

因为确定数据范围是一件痛苦的事,小Q出了非常多的题目之后,都没有它们设置数据范围。对于一道题目,小Q会告诉你他的算法的时间复杂度为 O(nalogbn),且蕴含在这个大 O记号下的常数为 1。同时,小Q还会告诉你评测机在规定时限内可以执行 k条指令。小Q认为只要 na(log2n)b不超过 k,那么就是合理的数据范围。其中, x表示最小的不小于 x的正整数,即 x上取整。

自然,小Q希望题目的数据范围 n
越大越好,他希望你写一个程序帮助他设置最大的数据范围。
Input 第一行包含一个正整数 T(1T1000),表示测试数据的组数。

每组数据包含一行三个正整数 a,b,k(1a,b10,106k1018),分别描述时间复杂度以及允许的指令数。 Output 对于每组数据,输出一行一个正整数 n,即最大可能的 n。 Sample Input
3
1 1 100000000
2 1 100000000
1 3 200000000
Sample Output
4347826
2886
48828

思路:题意就是已知a,b,和k,在满足na(log2n)bn的a(log2n)bna(log2n<=K的情况下,求满足该条件的最大的n的值。

读懂题意后大致知道需要用二分,但是额是个二分刚刚入门的小菜鸟,精度问题(即是l<=r还是来l<r,是l=m还是l<=m+1)

实在不知道什么时候用,就参考一下别人的精度控制,以后继续学习


在求解 log2n⌉时需要用到反函数的相关知识,如求解2a=n时,两侧同时取对数,既可以得到a=log2n的解n的a(log2n)blog2n⌉时===n的a(log2n)b 2nlog2n
c++代码如下:

#include<stdio.h>
#include<string.h>
typedef long long int ll;
#define inf 1000000000000000011
#include<algorithm>
using namespace std;
ll a,b,k;
ll pan1(ll x,ll y)   //快速幂
{
    ll num=1;
    while(y){
        if(y%2!=0)
            num*=x;
        x*=x;
        y/=2;
    }

    return num;
}
ll log2(ll m)   //两侧同时取对数,可以求得log2的n的向上取整的值
{
    ll i;
    for(i=1;i<=64;i++){
        if(pan1(2,i)>=m)
            return i;
    }
}
int panduan(ll mid)
{
    ll i,m;
    ll num1=1,num2=1;

    for(i=0;i<a;i++){
        if(num1<k/mid)
            num1*=mid;
        else
            return 0;
    }

    m=log2(mid);
    if(m==0)
        return 1;  //n=1,n小了
    else{
        num2=1;
        for(i=0;i<b;i++){
            if(num2<=k/m)
                num2*=m;  //a的m次幂
            else
                return 0;  //数据过大
        }
    }

    if(num1<=k/num2)
        return 1;
    else
        return 0;
}
int main()
{
    ll f,l,r,mid;
    scanf("%lld",&f);

    while(f--){

        scanf("%lld %lld %lld",&a,&b,&k);

        l=0; r=inf;
        while(l<=r){
            mid=(l+r)/2;
            if(panduan(mid)==1)
                l=mid+1;
            else
                r=mid-1;
        }

        printf("%lld\n",r);
    }

    return 0;
}
二分一定要控制精度。。。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值