提问给你两个整数x,y

给你两个整数 x, y. 需要你求出两个数 a, b. 满足对 x 乘 a 次 b 等于 y (即 x * ba = y).

例如 x=4, y=100时, 存在 a=2, b=5. 使等式成立.
输入格式
第一行包含一个整数 t (1 ≤ t ≤ 104)表示测试用例的数量。
每个测试用例由一行包含两个整数 x 和 y (1≤ x,y ≤ 100).

输出格式
如果可以选择一对正整数 a 和 b 使得 x 等于 y 在上述过程之后,打印这两个整数。您打印的整数应不小于 1 并且不大于 109(可以证明,如果答案存在,则存在一对整数 a 和 b 满足这些约束)。如果有多个这样的数对,请输出其中任何一个。
如果无法选择一对整数 a 和 b 使得 x 等于 y,则输出整数 0 两次。

输入样例 复制
3
3 75
100 100
42 13
输出样例 复制
2 5
3 1
0 0

#include <stdio.h>
#include <math.h>

void find_a_b(int x, int y, int *a, int *b)
{
  *a = 0;
  *b = 0;
  if (y % x != 0) {
    // 如果y不能被x整除,则不存在满足条件的a和b
    return;
  }
  int i, j;
  double logyx, logx, logb;
  for (i = 2; i <= y; i++) {
    // b从2开始尝试,x的0次方是1,所以也需要包括1
    for (j = 0; ; j++) {
      logyx = log(y) / log(i + j);
      logx = log(x) / log(i + j);
      logb = fmod(logyx, logx);
      if (fabs(logb) < 1e-9) {
        // 找到了满足条件的b值
        *a = (int)(logyx / logx);
        *b = i + j;
        return;
      } else if (logb < 0) {
        // 如果b太大,就不必再尝试了
        break;
      }
    }
  }
}

int main()
{
  int t, x, y, a, b;
  scanf("%d", &t);
  while (t--) {
    // 读取输入数据
    scanf("%d%d", &x, &y);
    // 找到满足条件的a和b
    find_a_b(x, y, &a, &b);
    // 打印结果
    printf("%d %d\n", a, b);
  }
  return 0;
}


解题思路:

假设有方程

$$
a\times b ^ m = y
$$

因为 $a$ 与 $y$ 同乘以一个常数后结果不变,所以先令 $b=1$,$a=y$ 可得

$$
a=y,b=1,m=0
$$

显然这是一组解,并且是唯一的满足这个条件的解(因为 $m$ 不可能为负)。如果 $y$ 不能被 $x$ 整除,那么直接输出 0。

接下来我们从 $m=1$ 开始枚举 $m$,每次求出对应的 $b$,如果 $b$ 是整数,那么就是一组合法解,此时输出 $a$ 和 $b$ 即可。

判断数字是否为整数可以使用 math.isqrt() 函数,判断该数字的平方根是否为整数。

下面是C语言的实现:

#include<stdio.h>
#include<math.h>

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int x,y;
        scanf("%d%d",&x,&y);

        int flag=0;
        for(int i=1;i<=sqrt(y);i++)
        {
            int b=i,a=1;
            while(y%pow(x,a)==0)
            {
                a++;
            }
            if(pow(x,a-1)==pow(y,1.0/b))
            {
                printf("%d %d\n",a-1,b);
                flag=1;
                break;
            }
        }
        if(!flag) printf("0 0\n");
    }
    return 0;
}

解释一下其中的思路:

  • for 循环中,枚举 b 并依次判断;
  • 在内层 while 循环中,对 a 进行累加,直到不满足条件 $x^a=y^b$ 为止;
  • 判断条件 $x^{a-1}=y^{1/b}$ 是否成立,如果成立,输出 a-1 和 b;
  • 如果 for 循环结束后还没有找到符合条件的值,则输出 0 0。

这种解法的时间复杂度是 O(T sqrt(Y) log(Y)),其中 T 是测试用例的数量。