codeforces 题目 Make It Round

目录

题目:

题目描述:

思路:

AC代码:


题目:

题目描述:

对于每个案例,给你一对 n,m ,从1 ~ m中找一个数,我们不妨设为 x 。让 x 与 n 相乘。让乘积拥有更多的 0 的情况下更大。

对于输出:

①如果找到了合适的 x ,让 n * x 过后比 n 原本尾部的 0 更多了,就输出这个乘积

②如果找不到合适的 x 能让乘积过后尾部的 0 增多就输出 n * m 

思路:

总的来说这题是要让乘积过后尾部的 0 更多。所以我们要先想想一个数尾部的零个数跟什么有关?我们可以想到是只跟这个数的质因数分解中,质因子 2 的数量和质因子 5 的数量有关。

(第一关键字是尾部更多 0 ,第二关键字是乘积更大)。

前提提要

m ÷ a = b......c

a * b <= m

此时如果我们要求小于m的具有一个a因子的最大的数,那就是 a * b

得到最终的那个 “商(b)” 以及出发过程中的 “除数(a)” 及其 “次数” 就能得到x的值。

所以如果 m 想给出因子的话,就可以看看m是否大于 “除数”,如果大于的话,我们可以直接对 m 上进行除法,记录好当前的 “除数” 以及 “次数” 之后让( m = 商 )以应对下一次给出。

例子:

m == 65

65 ÷ 2 == 31 ......1

31 ÷ 2 == 15 ......1

15 ÷ 2 == 7 ......1

7 ÷ 5 == 1 ......2

x == 1 * 2 * 2 * 2 * 5 == 40

简单来说就是四步:

①尽可能从 m 中拿出 2/5因子,来补充n较少的 2/5因子以达到平衡

②从剩余的 m 中拿出尽可能多的 10因子(成对的拿出 2/5因子)、

③保留最后的商

④求最后答案


复杂的来说(不想听我BB可以直接看后面的AC代码)

①我们先来想想如何让乘积满足第一关键字———尾部更多的0

那么为了让 n * x 之后尾部有最多的 0 ,我们就需要让( n 和 x 的所有 2 和 5 的因子中数量少的那个)量更多。

所以我们可以通过两个while循环求得 n 中有多少 2因子和 5因子,同时将 n 中的 2因子 5因子除干净方便后面计算。

那么问题又来了,我们怎么在 1 ~ m 中选 x 才能适配上面的最优情况呢?

我们应该先尽可能给 n 补充( n 中 2因子和 5因子)中数量较少的那个,也就是如果( m/2 > 0 )或者( m/5 > 0 )说明 m 还能给出 2/5因子。直到现在 n 中的 2/5因子加上 m 给出的 2/5因子数量平衡了,抑或是 m 给不出来了,就停止。

然后我们再看如果( m/10 > 0 ),剩余的还能给出 10因子(同时给出 2和5因子)

②让乘积满足第二关键字———尽可能的大

我们只需要将上面剩下的那个小于 10 的 m 也乘给 n 就行

具体如何操作的请看一下AC代码

AC代码:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

ll qsm(ll a, ll b)
{
	ll sum = 1;

	while (b)
	{
		if (b & 1)
			sum *= a;
		a = a * a;
		b >>= 1;
	}

	return sum;
}

int main()
{
	std::ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);


	int t; cin >> t;

	while (t--)
	{
		ll n, m;
		cin >> n >> m;

		ll temp = n * m;

		ll er = 0;        //n本身具有的2
		ll wu = 0;        //n本身具有的5
		ll adder = 0;     //可以增加的2
		ll addwu = 0;     //可以增加的5

		while (n % 2 == 0)
		{
			er++;
			n /= 2;
		}

		while (n % 5 == 0)
		{
			wu++;
			n /= 5;
		}


		if (er > wu)
		{
			while (m >= 5 && addwu < er - wu)
			{
				m /= 5;
				addwu++;
			}
		}
		else if (er < wu)
		{
			while (m >= 2 && adder < wu - er)
			{
				m /= 2;
				adder++;
			}
		}

		while (m > 10)
		{
			adder++;
			addwu++;
			m /= 10;
		}



		if (adder || addwu)
			cout << n * m * qsm(2, er + adder) * qsm(5, wu + addwu) << '\n';
		else
			cout << temp << '\n';

	}

	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值