AcWing 1381. 阶乘(传送门)
思路分析:
这里给提供两种参考思路
第一种
我们进行观察,因为0只可能由2的倍数和5的倍数相乘得到,所以在进行乘法的过程中,我们将2和5的倍数给清理掉,这样就保证了不会出现0,然后我们控制其范围,每次相乘取其个位,因为个位肯定是非零元素,十位以后的数字完全没有必要保留下来,最后,我们将多处理的2或者5重新乘回去再取余即可。
利用的知识有:数论中的约数、同余定理
AC代码:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main() {
int n;
while (cin >> n) {
int res = 1;
int d2 = 0, d5 = 0;
for (int i = 1; i <= n; i++) {
int num = i;
// 先处理掉 2 和 5
while(num % 2 == 0) {
num /= 2;
d2++;
}
while(num % 5 == 0) {
num /= 5;
d5++;
}
// 前面的处理保证了个位不会出现 0
res = res * num % 10;
}
// 2 的因数要多余 5
// 这里的话,处理一下多余的2
for(int i = 0;i < d2 -d5;i++)
res = res * 2 % 10;
cout << res << endl;
}
return 0;
}
如果不放心 2 和 5 谁多的话,也可以选最小值处理下,但这貌似是个数论中约数的结论
int k = min(d2,d5);
for(int i = 0;i<d2-k;i++)
res = res * 2 % 10;
for(int i = 0;i<d5 - k;i++)
res = res * 5 % 10;
第二种:
第二种是比较容易想到的思维
只要 MOD 给的合理就行 这里的话 N 的范围是 1-1000,然而 1000 * 1000 也最多6个0 ,所以 MOD 只要比 1e6大应该都可以(当然是在保证不溢出的情况下),保险起见给了个1e9 ,后实战测试 1e3 就能过
AC代码:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int mod = 1e9;
int main() {
int n;
while (cin >> n) {
ll res = 1;
for(int i = 1;i<=n;i++) {
res *= i;
// 如果有尾数有 0 处理掉
while(res % 10 == 0) {
res /= 10;
}
res = res % mod;
}
// 最后只要非 0 的个位
res = res % 10;
cout << res << endl;
}
return 0;
}