hdu-5505 数论

题目大意:给你两个数N和M,N每次可以乘以N的一个因数变成一个新的N,问至少进行多少步操作才能使得N变成M?如果不能变成M,那么输出-1。


分析:既然N每次乘以一个自己的因数,那么一开始组成N的质因数自始至终都不会改变,而且这些质因数上的指数只会增加(或者不变),不可能减小。那么我们就可以得到:组成N的所有质因数M都有,组成M的所有质因数N都有,也就是说N和M的质因数集合是一样的。而且这道题目N比较小,M比较大,那么我们优先分解N。对于N的每个质因数p,要保证M能够被p整除,而且M能够被N的所有质因数除干净。对于N的一个质因数P,不妨设N相对于P的指数是k,M相对于P的指数是s,那么首先需要保证的是k是小于等于s的。然后,为了使得k尽快变成s,那么k每次最多乘以2,那么至少需要ceil( log2( s / k ))步,然后把所有的质因数P需要的步数中取出最大值,就是结果!


代码:

#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")

using namespace std;
#define   maxn          1000+10
#define   lson          l,m,rt<<1
#define   rson          m+1,r,rt<<1|1
#define   clr(x,y)      memset(x,y,sizeof(x))
#define   rep(i,n)      for(int i=0;i<(n);i++)
#define   repf(i,a,b)   for(int i=(a);i<=(b);i++)
#define   pii           pair<int,int>
#define   mp            make_pair
#define   FI            first
#define   SE            second
#define   IT            iterator
#define   PB            push_back
#define   Times         10

typedef   long long     ll;
typedef   unsigned long long ull;
typedef   long double   ld;

const double eps = 1e-10;
const double  pi = acos(-1.0);
const  ll    mod = 1e9+7;
const  int   inf = 0x3f3f3f3f;

inline void RI(int& x)
{
    x=0;
    char c=getchar();
    while(!((c>='0'&&c<='9')||c=='-'))c=getchar();
    bool flag=1;
    if(c=='-')
    {
        flag=0;
        c=getchar();
    }
    while(c<='9'&&c>='0')
    {
        x=x*10+c-'0';
        c=getchar();
    }
    if(!flag)x=-x;
}

//--------------------------------------------------


int tot=0;
int prime[maxn];
bool isprime[maxn];
void init(int n){
	for(int i=2;i<=n;i++){
		if(!isprime[i])
			prime[tot++]=i;
		for(int j=0;1ll*prime[j]*i<=n;j++){
			isprime[prime[j]*i]=true;
			if(i%prime[j]==0)break;
		}
	}
}
int solve(int n,ll m){
	int maxx=0;
	for(int i=0;i<tot&&prime[i]<=n;i++)
		if(n%prime[i]==0){
			int k=0,s=0;
			if(m%prime[i])return -1;
			while(n%prime[i]==0){
				k++;
				n/=prime[i];
			}
			while(m%prime[i]==0){
				s++;
				m/=prime[i];
			}
			if(k>s)return -1;
			maxx=max(maxx,(int)ceil(log(1.0*s/k)/log(2)));
		}
	if(n>1){
		if(m%n)return -1;
		int k=1,s=0;
		while(m%n==0){
			s++;
			m/=n;
		}
		maxx=max(maxx,(int)ceil(log(1.0*s)/log(2)));
	}
	if(m>1)return -1;
	else return maxx;
}
int main(){
	//freopen("d:\\acm\\in.in","r",stdin);
	init(1000);
	int t;
	scanf("%d",&t);
	while(t--){
		int n;
		ll m;
		scanf("%d %lld",&n,&m);
		printf("%d\n",solve(n,m));
	}
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值