题目的意思是说,两个人刚刚开始游戏的时候的分数, 都是一分, 然后随机一个人的分数扩大k倍,另一个扩大k的平方倍, 问给你一组最后得分,问能不能通过游戏得到这样一组得分。(谁扩大k倍, 谁扩大k的平方倍,是可以自由选择的, k的值只要是自然数就行了)。
题目做法: 对输入的两个数a, b。求(a*b) 的1/3次方, 如果不能得到,就是不能得的输出“No”。否则在看开方得到的数,能不能同时被a和b整除, 如果可以就输出“Yes”,否则就是“No”。
如何证明呢? 其实也很简单,由于两边一个扩大k倍, 一个扩大k^2 倍, 所以对a*b来说一定扩大了,k^3倍,如果不满足就一定是“No”,但是满足了不一定是“Yes”, 比如这样2, 32,这两个数。所以再限制一下就可以了,可以证明的到:
设在第一个判定条件成立的情况下:a*b 可以化简成 k1^(3*n1) * k2(3*n2)……ki(3*ni)。这里k1, k2……ki为素数, ni为整数。 由于第一个判定条件成立,一定可以化简成这样的情况。在满足两边都能被整除的情况下,每边都有(k1^n1 * k2^n2 * k3^n3 * …… ki^ni)这样一组, 所以外面还剩下一组(k1^n1 * k2^n2 * k3^n3 * …… ki^ni)。为了方便证明我们现在只证明k1 是可以满足的,那么其余的也都可以满足。设a分的剩下n1个k1中的x个, 那么b分得了(n1-x) 个, 设在整个游戏中 对于a来说获得乘k^2的次数为m1次,获得乘k的次数为m2次那么,对于b就是反过来的。所以满足一下两个等式:
n1 + x - m1 * 2 - m2 == 0
n1 + n1 - x - m1 - 2 * m2 == 0
可以通过简单的化简,以上等式恒成立, 所以,无论x的值是多少,最后的结果都是对的。以上得证。
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
#include <math.h>
using namespace std;
#define Max_N (1000000+100)
long long int a, b;
long long int c;
int n;
long long int k1;
long long int c1;
int main()
{
scanf("%d", &n);
while (n--) {
c1 = 0;
scanf("%lld%lld", &a, &b);
k1 = a*b;
c = int(pow(k1, 1.0/3));//由于pow函数有精度误差所以下面做法可以消除这个。
if (c * c * c == a*b) {
c1 = c;
}
else if ((c-1) * (c-1) * (c-1) == a*b) c1 = c-1;
else if ((c+1) * (c+1) * (c+1) == a*b) c1 = c+1;
if (c1 == 0) {
printf("No\n");
continue;
}
else {
if (a%c1 == 0 && b%c1 == 0)
printf("Yes\n");
else printf("No\n");
}
}
return 0;
}