当前位置:编程学习 > C/C++ >>

HDU 4282 A very hard mathematic problem(12天津网络赛-数学)

题目链接:Click here~~
题意:
给你一个式子x^z + y^z + x*y*z = k,k 为给定的某个int 范围内的数字。
求共有多少组关于x,y,z 的解。(0< x < y,z > 1)
解题思路:
这题纠结了2天,我擦。今天终于把错误拍出来了。
观察式子不难发现,显然当z 越大的时候x,y 的值越小。
由于y 最小等于2,所以有2^z < k,又k < 2^31,所以有z < 31。
1、首先考虑当z=2 的时候,式子左边可以化为(x+y)^2 = k 的形式。
所以当k 是完全平方数的时候,(x,y) 才有可能有解。
假如m^2 = k ,问题就相当于求x+y = m (x < y) 的解的组数。
容易得出,当m为偶数时,解组数为m/2-1;当m为奇数时,解组数为(m-1)/2。
2、然后考虑当z>=3 的时候。
当z=3 的时候,x,y 可能取到的值最大,而稍加计算可以得出y 的最大值是1290.xx,设这个值为M。
那么枚举x,z的复杂度变为O(M*30),大概是O(10^4)。
如果再直接枚举y的话,复杂度为O(M^2 *30),大概是O(10^7),略大。(不过也能140MS AC)。
那么有没有好的方法呢?
显然当x,z 确定后,式子关于y 是单调递增的,于是可以二分,将复杂度降为O(M*logM*30),大概是O(10^5)。(15MS AC)。
第一次用小号交的,爆了0MS,然后竟然排到了rank1。O(∩_∩)O...
Ps:思路一直都是对的,可是昨天WA了一天。
这种题要注意一些细节。在二分的时候,我y 的右边界一直取的是当z = 3的时候的M。这种贪方便的做易做图引发一个问题。
就是当z 逐渐变大的时候,二分区间中很多的值会溢出long long 的范围,导致判断大小错误。
幸好值溢出时会变负,所以我们可以根据值是否为负来判断是否溢出。若溢出,直接等效于大于。
[cpp] 
#include <stdio.h> 
#include <math.h> 
 
typedef __int64 LL; 
 
int k,x,y,z; 
 
LL xz,yz; 
 
LL myPow(int a,int n) 

    LL ans = a; 
    while(--n) 
        ans *= a; 
    return ans; 

 
LL fun(int Y) 

    return xz + yz + x*Y*z; 

 
bool FindIt(int l,int r) 

    while(l <= r) 
    { 
        int mid = (l+r)/2; 
        yz = myPow(mid,z); 
        LL f = fun(mid); 
        if(f == k) 
            return true; 
        if(f<0 || f>k) 
            r = mid-1; 
        else 
            l = mid+1; 
    } 
    return false; 

 
int main() 

    while(scanf("%d",&k),k) 
    { 
        int ans = 0; 
        int sq = sqrt(k*1.0); 
        if(sq*sq == k) 
            ans += (sq-1)/2; 
        for(z=3;z<31;z++) 
        { 
            for(x=1;;x++) 
            { 
                xz = myPow(x,z); 
                if(xz >= k/2) 
                    break; 
                if(FindIt(x+1,1300)) 
                    ans++; 
            } 
        } 
        printf("%d\n",ans); 
    } 
    return 0; 
补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,