【佛山市选2009】有道难题

\(Description\)

从前有个人,叫好人。他非常擅长解决数学问题。今天他正在做这样的一道数学题:
给定三个正整数 \(X\) , \(Y\)\(Z\) \((X < Y, Z > 1)\) 满足
   \[ X ^ Z + Y ^ Z + X Y Z = K \]
其中 \(K\) 是另一个给定的正整数。
找出该问题的一个解方案对好人来说是非常简单的事。现在,他想继续挑战一下:该等式总共有多少组不同的解方案呢?
意外的是,这个好人居然做不出来。看来,这是一道难题。现在,是你的 \(show time\) 了。

\(Input\)

输入包含多组数据。
对于每组数据,只有一个整数 \(K\)
\(K = 0\) 时表示输入结束。

\(Output\)

对每组数据,输出一行,仅包含一个整数,表示解方案的个数。

\(Sample Input\)

9
53
6
0

\(Sample Output\)

1
1
0

\(Hint\)

【样例解释】

\(9 = 1 ^ 2 + 2 ^ 2 + 1 * 2 * 2\)

\(53 = 2 ^ 3 + 3 ^ 3 + 2 * 3 *3\)

【数据说明】
  对于 50% 的数据,\(0 < K < 100000\)
  对于 100% 的数据,\(0 < K < 2^31\)

解析

暴力瞎搞,容易想到
考虑先枚举一个 \(z\) ,易知 \(x,y\) 的范围是 \(1\)\(\lfloor \sqrt[z] k \rfloor\)
暴力枚举 \(x\),从 \(1\) 开始,每次加 \(1\)
\(y\) 先指向 \(\lfloor \sqrt[z] k \rfloor\)
\(x,y,z\) 代入计算
若值大了,缩小 \(y\);等于记贡献;小于 \(break\)\(x + 1\)
而再进入枚举 \(y\) 时,不需要重新指向 \(\lfloor \sqrt[z] k \rfloor\)
因为 \(x\) 变大了,\(y\) 就不可能比上次大
所以 \(y\) 最多移动 \(\lfloor \sqrt[z] k \rfloor\)
因而时间复杂度约莫是:
\[ O(log_2 k·log_2^2k·\sqrt[z] k) \]

代码

#include<cstdio>
using namespace std;
typedef long long LL;

inline LL fpow(LL x , LL y)
{
    LL res = 1;
    while (y)
    {
        if (y & 1) res = res * x;
        x = x * x , y >>= 1; 
    }
    return res;
}

inline LL yroot(int x , int y)
{
    LL res = 1;
    while (fpow(res , y) <= x) res++;
    return (fpow(res , y) == x ? res : res - 1);
}

int main()
{
    register LL k , ans , _k;
    scanf("%d" , &k);
    while (k != 0)
    {
        ans = 0;
        for(register LL z = 2; z <= 30; z++)
        {
            LL l = yroot(k , z) , y = l;
            for(register LL x = 1; x <= l; x++)
                while (y && y > x)
                {
                    _k = fpow(x , z) + fpow(y , z) + x * y * z;
                    if (_k == k) ans++;
                    if (_k <= k) break;
                    y--;
                }
        }
        printf("%d\n" , ans);
        scanf("%d" , &k);
    }
}

小巧玲珑,愉快 \(AC\)

猜你喜欢

转载自www.cnblogs.com/leiyuanze/p/12181086.html