题目
现在给出数字Q,请找到最小的N,使得N!末尾恰好有Q个0
输入格式
输入一个整数Q(1<=Q<=10^8)
输出格式
如果无解,输出"No solution",否则输出 N 。
题解:
多一个0相当于乘以一个10,10可以拆解为2*5,因为2的数量远多于5,所以题目可以转换为:求0的个数->5的个数。
代码:
法一:
从左到右逐个累加因子5的数量直至达到要求Q
#include <iostream>
using namespace std;
int main()
{
int Q, i, count, cnt;
cin >> Q;
if (Q == 0)
{
cout << "0";
return 0;
}
for (i = 5, count = 0; count < Q; i += 5) {
int t = i; cnt = i;
//i=5,i+=5。使得给出的所以数第一次都能进入,即5的数量至少加一,但如30,其除以5后得6,则无法再次进入,而25可以。
while (t % 5 == 0)
{
count++;
t /= 5;
}
}
if (count == Q)
cout << cnt;
else
cout << "No solution";
return 0;
}
法二:
二分查找法
/*法2:二分法*/
#include <iostream>
using namespace std;
//统计n!中5的数量,并返回
int countTrailingZeros(int n) {
int count = 0;
while (n > 0) {
n /= 5;
count += n;
}
return count;
}
int main() {
int Q;
cin >> Q;
//阶乘末尾要有Q个0,那么对应的边界N最大为Q*5
int low = 0, high = Q * 5;
//假设找不到,如果找到会改变ans值
int ans = -1;
while (low <= high) {
int mid = (low + high) / 2;
int zeros = countTrailingZeros(mid);
if (zeros == Q) {
//改变ans值,表明可以找到
ans = mid;
//虽然找到了末尾Q个0对应的N!,但因为high是经过放大了的,所以这个N并不是最小的解,需要将右值继续左移
high = mid - 1;//或者high=high-1
}
else if (zeros < Q) {
low = mid + 1;
}
else {
high = mid - 1;
}
}
if (ans != -1) {
cout << ans;
}
else {
cout << "No solution";
}
return 0;
}