目录
题目:
题目描述:
对于每个案例,给你一对 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;
}