2020-2-16 B - Math

题目如下:
JATC’s math teacher always gives the class some interesting math problems so that they don’t get bored. Today the problem is as follows. Given an integer n, you can perform the following operations zero or more times:

mul x: multiplies n by x (where x is an arbitrary positive integer).
sqrt: replaces n with n−−√ (to apply this operation, n−−√ must be an integer).
You can perform these operations as many times as you like. What is the minimum value of n, that can be achieved and what is the minimum number of operations, to achieve that minimum value?

Apparently, no one in the class knows the answer to this problem, maybe you can help them?

Input
The only line of the input contains a single integer n (1≤n≤106) — the initial number.

Output
Print two integers: the minimum integer n that can be achieved using the described operations and the minimum number of operations required.

Examples
Input
20
Output
10 2
Input
5184
Output
6 4
Note
In the first example, you can apply the operation mul 5 to get 100 and then sqrt to get 10.

In the second example, you can first apply sqrt to get 72, then mul 18 to get 1296 and finally two more sqrt and you get 6.

Note, that even if the initial value of n is less or equal 106, it can still become greater than 106 after applying one or more operations.

题意:
大概是输入一个数,用平方根和乘法对其进行运算,使其达到最小值并输出结果和最小步骤数。

思路:
一开始看到这个题的时候想用暴力,但是一想不太行,后来翻看到老的文章,看到了因数二字,心中有了想法。。。
一个数由好多最小因数组成,经过这一系列运算,那个最小的数就是所有可能因子的乘积
那一系列运算究竟是什么样的运算呢?怎么安排乘法和开方?
后来一想,哦,想要达到最小值得让那些因数的个数变为偶数才可以进行开方,乘法无异于是引入因数,让其个数变为偶数, 乘法只需要进行一次即可
为了让每个因数的个数都变为1,前提是需保证个数最多的那个因数的个数变为1,并且需要将其个数变为2的幂次方(>=原个数)再求log2就是总体需要开方的次数,如果前面的乘法运算存在的话开方次数+1就是总共要运算的次数

我的AC代码:

#include <iostream>
#include <cmath>
#define LL long long int
using namespace std;

struct note{
	int a;
	int n;
};
struct note yin[20];

int f(int p){

	int top = (int)sqrt((double)p);
	int i;
	for(i = 2; i <= top; i++){
		if(p % i == 0) return i;
	}
	return p;//最小因子就是他自己。。。。 
}

int main(void){
	LL in; cin>>in;

	int head = 0,tail = 0;
	int i;
	
	int flag;
	while(in != 1){//获得所有因子信息 
		int tyin = f(in);
		flag = 0;
		for(i = head; i < tail; i++){
			if(yin[i].a == tyin){
				yin[i].n++;
				flag = 1;
			}
		}
		if(flag != 1){
			yin[tail].a = tyin;
			yin[tail].n  = 1;
			tail++;
		}
		in /= tyin;
	}
	
	int k = 1;
	for(i = head; i < tail; i++) k *= yin[i].a; 
	

	int maxer = -1;
	for(i = head; i < tail; i++) maxer = max(maxer, yin[i].n);
	
	int ce = 1;
	while(ce < maxer) ce *= 2;
	
	int step = 0;		
	for(i = head; i < tail; i++) 
		if(ce != yin[i].n){
			step++;
			break;
		}
	while(ce != 1){
		ce /= 2;
		step++;
	}
	
	cout<<k<<" "<<step<<endl;
	return 0;
} 

修改和加注释以后的代码:

#include <iostream>
#include <cmath>
#define LL long long int
using namespace std;

struct note{
	int a;
	int n;
};

int f(int p){//求最小因子的函数 
	int top = (int)sqrt((double)p);
	int i;
	for(i = 2; i <= top; i++){ //如果输入2,3 这里并不执行 
		if(p % i == 0) return i;
	}
	return p;//最小因子就是他自己。。。。
}

int main(void){
	int in; cin>>in;
	struct note yin[20];
	int head = 0,tail = 0;//用个队列存储 
	int i;
	
	int flag;
	while(in != 1){//获得所有因数及其个数 
		int t = f(in);
		for(i = head; i < tail; i++){//扫描是否已经被记录 
			if(yin[i].a == t){//有的话个数+1 
				yin[i].n++;
				break;
			}
		}
		if(i == tail){//没有记录 //这里对flag进行了优化 
			yin[tail].a = t;
			yin[tail].n  = 1;
			tail++;//入队操作 
		}
		in /= t;//除以那个因数 
	}
	
	int miner = 1;
	int maxer = -1;	
	for(i = head; i < tail; i++){
		maxer = max(maxer, yin[i].n);//找到个数最多的那个因数 
		miner *= yin[i].a; //求出那个最小值 
	} 

	int step = 0;
	int base = 1;
	while(base < maxer){//求出最小二次幂值 
		base *= 2;
		step++;
	}
	for(i = head; i < tail; i++) //判断是否进行了乘法操作 	
		if(base > yin[i].n){
			step++;
			break;
		}
	
	cout<<miner<<" "<<step<<endl;
	return 0;
} 

*开方就是指数除以2

*乘法就是引入因数

题目让求最小值,那就要去考虑给定的操作可以让数的属性发生哪些变化

再看一下dalao的思路

#include<iostream>
using namespace std;
int main(void)
{
	long long int n; cin >> n;

	if (n == 1) cout << "1 0" << endl;
	else {
		long long int ans = 1, num = 0, m = n;
		int i;
		for (i = 2; ; i++) {
			if (m == 1) break;
			if (m % i == 0) ans *= i;//如果是因数,载入
			while (m % i == 0) m /= i;//然后把这个因数消除掉
		}
		long long int x = ans;
		while (x % n) {//被除尽还有这样一层含义。。。
			x *= x;//这里也很妙,用乘法代替开开方
			num++;
		}
		if (x > n) num++;//这个是否进行过乘法运算的判断也很妙
		cout << ans << " " << num << endl;
	}
	return 0;
}

hhhh这简洁性这效率 又被大佬摁在地上摩擦 orz

花时间整理,之后一定常来看哦~ (/ω\)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值