Math

题目大意:

JATC的数学老师为了不让同学们感到厌倦,总是出一些有趣的题目。今天的题目是这样的:
给定一个整数n,您可以对它进行如下操作:

  • 乘以x:把n乘上x(x是任意正整数)。
  • 开方:把n的值更新为sqrt{n} (前提是\sqrt{n}必须为整数)。

您可以对这些操作进行零次至任意次。那么n可以达到的最小值是多少 ?达到最小值需要进行操作的次数又是多少?
显然,班里没有同学能够解决这个问题,您能够帮帮他吗?

题解:

一开始确实没什么头绪。。。。但是当把样例里面的n进行质因数分解后,再与答案进行对比,有了奇怪的发现。
首先把一个数分解为a^x1 * b^x2 * c^x3 * ......d^ x..其中a,b,c....等数都为质数,显然,这些质数是不能通过开方运算来消除的,因此,所能得到的最小数就是这些质数相乘的结果。
解决了最小数的问题,那么怎么得到最少的步数呢?由于是开方运算,每开一次方,所有质数的质数都除以二,我们最终的目标是把所有质数的质数都降为1,所以通过一次乘法将所有质数的指数都变为2^y是一定要做的,所得到的y,加上你做的一次乘法就是步数

具体的步骤

  • 对原数进行质因数分解,找到能得到的最小的数
  • 检查每个质数的次数是否都为2^y,否则会进行一次乘法,步数在y的基础上加一
  • 输出答案
点击查看代码
#include<bits/stdc++.h>
using namespace std;
bool vis[10000005];
vector<int> prime;
struct num{
	int n,t;
	num(){}
	num(int nn,int tt){
		n = nn;
		t = tt;
	}
};//记录分解后每个质数及其次数,n为该质数 
vector<num> divv;
int m;
int x(){//求得最小的y 
	int now = 1;
	int tim = 0;
	while(now < m){
		now *= 2;
		tim++;
	}
	return tim;
}
int main(){
	int d;
	cin >> d;
	if(d == 1){//特殊情况特殊处理 
		cout << 1 << " 0" ;
		return 0;
	}
	for(int i = 2; i <= 1000005; i++){//线性筛法,得到数据范围内的质数,便于质因数分解 
		if(!vis[i]){
			vis[i] = 1;
			prime.push_back(i);
		}
		for(int j = 0; j < prime.size(); j++){
			if(i * prime[j] > 1000005)break;
			vis[i * prime[j]]= 1;
			if(i % prime[j] == 0)break;
		}
	}
	int cnt = 0,time = 0;
	while(1){
		if(d % prime[cnt] == 0){ 
			d /= prime[cnt];
			time++;
		}
		else{
			if(time != 0)divv.push_back(num(prime[cnt],time));//质因数分解并做记录 
			cnt++;
			time = 0;
		}
		if(d == 1 && time == 0)break;
	}
	int ans = 1;
	bool flag = 1;
	for(int i = 0; i < divv.size(); i++){//检查一下是否需要进行一次乘法 
		if(i >= 1){
			if(divv[i - 1].t != divv[i].t)flag = 0;//如果不能做到任意两个质数之间的次数相等,那么需要做一次乘法,先做一个标记 
		}
		ans *= divv[i].n;
		m = max(m,divv[i].t);
	}
	int g = pow(2,x());
	
	if(g == m && flag){
		cout << ans << " " << x();
	}
	else if(g > m || !flag){//如果有质数之间的次数不相等或者所有质数的次数相等但不是2^y这样的形式,就需要做一次乘法 
		cout << ans << " " << x() + 1;
	} 
}
posted @ 2022-07-11 21:51  腾云今天首飞了吗  阅读(84)  评论(0编辑  收藏  举报