1. 程式人生 > >杭電acm 4282 A very hard mathematic problem

杭電acm 4282 A very hard mathematic problem

Haoren is very good at solving mathematic problems. Today he is working a problem like this:
  Find three positive integers X, Y and Z (X < Y, Z > 1) that holds
   X^Z + Y^Z + XYZ = K
  where K is another given integer.
  Here the operator “^” means power, e.g., 2^3 = 2 * 2 * 2.
  Finding a solution is quite easy to Haoren. Now he wants to challenge more: What’s the total number of different solutions?
  Surprisingly, he is unable to solve this one. It seems that it’s really a very hard mathematic problem.
  Now, it’s your turn.


Input
  There are multiple test cases.
  For each case, there is only one integer K (0 < K < 2^31) in a line.
  K = 0 implies the end of input.
  


Output
  Output the total number of solutions in a line for each test case.


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

解題思路:我相信大家剛看到本題時,都會想到暴力,但又看了看會覺得暴力超時呀!的確,本題直接用暴力會超時,但是,我們不妨換一種思路,當z=2時,x^z + y^z +x*y*z=(x+y)^2=k,即x+y=sqrt(k),那麼只需要在1~2^16範圍內來判斷,並且這裡擁有一個小規律,組合數ant = (sqrt(k) - 1)/2(這個僅在sqrt(k)是整數時成立,非整數時無解);

那麼接下來只需要判斷z>=3&&z<=31時的情況了,根據化簡此時x<y<=1124(這裡只要大於1024即可),於是直接暴力,但是別忘了剪枝,否則依舊會超時。

程式碼如下:

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

using namespace std;

long long Pow(int x,int n)//本題需要自己編寫pow函式,呼叫系統函式會超時。
{
      long long ans = 1;
      for(int i=1;i<=n;i++)
            ans *= x;
      return ans;
}

int main()
{
      long long k;
      int x,y,z;
      while(scanf("%lld",&k)!=EOF && k)
      {
            long long ant = 0;
            int a = (int)sqrt(k);
            if(a*a*1.0 == k)//進行z=2的判斷
                  ant+=(a-1)/2;
            for(z=3;z<=31;z++)//對z>=3的情況進行暴力求解。
            {
                  for(x=1;x<=1100;x++)
                  {
                        if(Pow(x,z) >= k)       break;//剪枝
                        for(y=x+1;y<=1100;y++)
                        {
                              long long ans = Pow(x,z)+Pow(y,z) + x*y*z;
                              if(ans == k)
                              {
                                    ant++;
                                    break;
                              }
                              else if(ans > k || ans < 0)   break;//剪枝
                        }
                  }
            }
            printf("%lld\n",ant);
      }
      return 0;
}