CF833A The Meaningless Game 数学
分析
这道题有一点点数学的感觉(其实我只是看到了平方),来分析一下,两个人的初始值都一样,只知道最后的结果,中间的过程我们是不知道的,但可以很明显的看出,只要我的操作合法,两个数的乘积就一共扩大了\(k^3\)倍,所以关键的就是确定这个\(k\)是啥。
直接枚举是显然不可以的,需要找一些共性的东西,于是就想到了分解质因数。只要我分解出来的每个质因数,第一个数的个数和第二个数的个数加起来一定是3的倍数。因为\(k\)可以分解为\(p_1,p_2……p_n\),\(k^2\)就是把每个质因数都平方,所以一次操作就相当于多了3,说的可能绕了一些,反正就是这样。
这么写的正确性肯定是毋庸置疑的,但时间消耗会很大,尤其是涉及到取%的操作很多,于是就TLE了。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e6+10;
int prime[N];
bool isp[N];
void init(){
memset(isp,1,sizeof(isp));
for(int i=2;i<=N-5;i++){
if(isp[i])
prime[++prime[0]]=i;
for(int j=1;j<=prime[0]&&i*prime[j]<=N-5;j++){
isp[i*prime[j]]=0;
if(i%isp[j]==0)break;
}
}
}
int num[N],cnt[N];
int prim(int n){
int mx=0;
memset(num,0,sizeof(num));
for(int i=1;prime[i]<=n&&i<=prime[0];i++){
while(n%prime[i]==0){
n/=prime[i];
num[prime[i]]++;
mx=i;
}
}
return mx;
}
int prim_(int n){
int mx=0;
memset(cnt,0,sizeof(cnt));
for(int i=1;prime[i]<=n&&i<=prime[0];i++){
while(n%prime[i]==0){
n/=prime[i];
cnt[prime[i]]++;
//printf("%d\n",prime[i]);
mx=i;
}
}
return mx;
}
int main(){
int T;
scanf("%d",&T);
init();
while(T--){
int a,b;
scanf("%d%d",&a,&b);
if(a==1||b==1){
printf("Yes\n");
continue;
}
int pa=prim(a),pb=prim_(b);
if(pa==0||pb==0||pa!=pb){
printf("No\n");
}
else {
bool ok=1;
for(int i=1;i<=pb;i++){
if((num[prime[i]]+cnt[prime[i]])%3!=0){
ok=0;break;
}
}
if(ok)printf("Yes\n");
else printf("No\n");
}
}
}
再想一下优化,其实没必要把每个质因数都枚举一遍,因为它又没让求是怎么分解的,所以直接对所有的整体的开三次方就好,然后这样就相当于开出了所有的质因数,先判断能不能开尽,再判断质因数就好。
#include<cstdio>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
const int N=1e6+10;
int main(){
int T;
scanf("%d",&T);
while(T--){
int a,b;
scanf("%d%d",&a,&b);
ll s=(long long)a*b;
ll x=pow(s,1.0/3)+0.5;
if(x*x*x!=s||a%x||b%x)
printf("No\n");
else printf("Yes\n");
}
}
int - > long long
0 - > 100