比赛的时候一直迷。。。应该手模一下的。。
题意:
问题描述
给出两个数N和M。 N每次可以乘上一个自己的因数变成新的N。 求最初的N到M至少需要几步。 如果永远也到不了输出−1。
输入描述
第一行读入一个数T表示数据组数。 接下来T行,每行两个数N和M。 T≤1000, 1≤N≤1000000,1≤M≤263. 注意M的范围。hack时建议输出最后一行的行末回车;每一行的结尾不要输出空格。
输出描述
对于每组数据,输出一个数表示答案。
输入样例
3 1 1 1 2 2 4
输出样例
0 -1 1思路:
首先把两个整数分解开来,然后先把一些特例判掉,然后去分别判断两个数的因子数量的不同个数,如果不同,对于某一个A的质因数的次数。为了加速接近B,它一定是每次翻倍,最后一次的时候把剩下的加上。
手模了一下,发现每次质因子都是扩大2倍,所以一直不停的乘以2就好,然后去找出所有质因子中进行次数最多的那个就好。
*hack点,很多人没有注意到范围是2^63次,所以这里要开unsigned __in64 才行,因为有符号的话范围刚好是2^63-1。
哦 还有map,vector没清零导致我一开始wa了几次。
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<map>
#include<vector>
using namespace std;
typedef unsigned __int64 LL;
LL n,m;
vector<LL> a1,a2,cou;
map<LL,LL> mp1,mp2,mp;
void prime(LL x,int f){
LL t=2;
while(x!=1){
bool ff=false;
while(x%t==0){
if(!f&&!ff) a1.push_back(t),ff=1;
else if(f&&!ff) a2.push_back(t),ff=1;
if(!f) mp1[t]++;
else if(f) mp2[t]++;
x=x/t;
}
t++;
}
}
int main(){
int T;
scanf("%d",&T);
while(T--){
mp1.clear(); mp2.clear();
mp.clear();
a1.clear(); a2.clear();
cou.clear();
scanf("%I64u%I64u",&n,&m);
if(n==1&&m!=1){
printf("-1\n");
continue;
}
if((n==1&&m==1)||(n==m)){
printf("0\n");
continue;
}
prime(n,0);
prime(m,1);
if(a1.size()!=a2.size()){
printf("-1\n");
continue;
}
int flag=1;
for(int i=0;i<a1.size();i++){
LL t1=a1[i],t2=a2[i];
if((!mp1[t1]&&mp2[t2])||(mp1[t1]&&!mp2[t2])){
printf("-1\n");
flag=0;
break;
}
}
if(!flag) continue;
int ff=1;
for(int i=0;i<a1.size();i++){
LL t=a1[i];
LL num1=mp1[t],num2=mp2[t];
if(num1>num2){
ff=0;
break;
}
LL tmp=num1;
if(tmp==num2){
mp[t]=0; continue;
}
int nn=0;
for(int j=1; ;j++){
tmp=tmp*2;
nn++;
if(tmp>=num2){
mp[t]=nn;
break;
}
}
}
if(!ff){
printf("-1\n");
continue;
}
LL lmax=0;
#if 1
for(int i=0;i<a1.size();i++){
LL t=a1[i];
lmax=max(lmax,mp[t]);
}
printf("%I64u\n",lmax);
#endif
}
}
/*
12
6 12
*/