HDU 6288 缺失的数据范围 (二分答案)

缺失的数据范围

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 512000/512000 K (Java/Others)
Total Submission(s): 1955    Accepted Submission(s): 408


Problem Description
著名出题人小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
 
  
31 1 1000000002 1 1000000001 3 200000000
 

Sample Output
 
  
4347826288648828
 

第一种:利用除法(long long)

/*
题意:找到n这个值

思路:直接对1e18进行二分答案。这里精度问题,所以用k来进行除法,看是否小于1. 

*/

#include<bits/stdc++.h>

using namespace std;
long long k,a,b;

bool check(long long x){
    long long y=(long long)ceil(log2(x));			//向上取整 
    long long ans=k;
    
    for(int i=0;i<a;i++){
        if(0<ans/x) ans/=x;
        else return true;
    }
    
    if(y==0) return false;			//0不能为除数 
    for(int i=0;i<b;i++){
        if(0<ans/y) ans/=y;
        else return true;
    }
    return false;
}


long long solve(){
    long long l=0,r=1e18,ans;
    while(l<=r){
        long long mid=(l+r)>>1;
        if(check(mid)){
            r=mid-1;
        }else{
            l=mid+1;
            ans=mid;
        }
    }
    return ans;
}

int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        printf("%lld%lld%lld",&a,&b,&k);
        printf("%lld\n",solve());
    } 
}

第二种:利用乘法和除法(unsigned long long)

/*
题意:找到n这个值

思路:直接对1e18进行二分答案。这里精度问题,用ans来进行除乘法,看是否大于k. 

*/

#include<bits/stdc++.h>

using namespace std;
unsigned long long k,a,b;

bool check(unsigned long long x){
    unsigned long long y=(unsigned long long)ceil(log2(x));   //向上取整 
    unsigned long long ans=1;
    for(int i=0;i<a;i++){
        if(ans>k/x) return true;      //先用除法判断,再用乘法 
        else ans*=x;
    }
    if(y==0) return false;
    for(int i=0;i<b;i++){
        if(ans>k/y) return true;
        else ans*=y;
    }
    return false;
}


unsigned long long solve(){
    unsigned long long l=0,r=1e18,ans;
    while(l<=r){
        unsigned long long mid=(l+r)>>1;
        if(check(mid)){
            r=mid-1;
        }else{
            l=mid+1;
            ans=mid;
        }
    }
    return ans;
}

int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        cin >> a >> b >> k;
        printf("%llu\n",solve());
    } 
}


第三种:利用乘法(long double)

/*
题意:找到n这个值

思路:直接对1e18进行二分答案。这里精度问题,所以用ans来进行乘法,看是否大于k.

*/

#include<bits/stdc++.h>

using namespace std;
long double k,a,b;

bool check(unsigned long long x){
    long double y=(long double)ceil(log2(x));
    long double ans=1;
    for(int i=0;i<a;i++){
        ans*=x;
        if(ans>k) return true;
    }
    if(y==0) return false;					//太小 
    for(int i=0;i<b;i++){
        ans*=y;
        if(ans>k) return true;
    }
    return false;
}


unsigned long long solve(){
    unsigned long long l=0,r=1e18,ans;
    while(l<=r){
        unsigned long long mid=(l+r)>>1;
        if(check(mid)){
            r=mid-1;
        }else{
            l=mid+1;
            ans=mid;
        }
    }
    return ans;
}

int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        cin >> a >> b >> k;
        cout<<solve()<<endl;
    } 
}


第四种:重写pow函数(long double到 自己测试到1e27)

/*
题意:找到n这个值

思路:直接对1e18进行二分答案。这里精度问题,重写pow函数,直接判断式子。 

*/

#include<bits/stdc++.h>

using namespace std;
long double k;
int a,b;

long double poww(unsigned long long x,int y){
    long double temp=x,res=1;
    while(y){
        if(y&1) res=res*temp;
        temp=temp*temp;
        y>>=1;
    }
    return res;
}

bool check(unsigned long long x){
    long double y=(long double)ceil(log2(x));
    long double ans=poww(x,a)*poww(y,b);
    if(ans>k) return true;
    else return false;
}


unsigned long long solve(){
    unsigned long long l=0,r=1e18,ans;
    while(l<=r){
        unsigned long long mid=(l+r)>>1;
        if(check(mid)){
            r=mid-1;
        }else{
            l=mid+1;
            ans=mid;
        }
    }
    return ans;
}

int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        cin >> a >> b >> k;
        cout<<solve()<<endl;
    } 
}

long double 测试:

#include<bits/stdc++.h>

using namespace std;

int main(){
	long double x=1e6;
	printf("%Lf\n",x);
	printf("%Lf\n",x*x);
	printf("%Lf\n",x*x*x);
	printf("%Lf\n",x*x*x*x);
	printf("%Lf\n",x*x*x*x*1000);
	printf("%Lf\n",x*x*x*x*10000);
} 

猜你喜欢

转载自blog.csdn.net/Rvelamen/article/details/81014396