爱思创 181111 阶乘之乘 题解

181111 阶乘之乘

题目大意

求出 \(1!*2!*3!*4!*……*n!\) 的末尾有几个零
小A:这跟题目有啥区别

铺垫知识

我们知道,\(n! = 1\times2\times3\times\dots\times n\)\((n - 1)! = 1\times2\times3\times\dots\times (n - 1)\)
小B: 那么我们可以推出 \(n! = n\times (n - 1)!\)

思路

先写一个大体模板

for(int i = 1; i <= n; i ++)
{
    for(int j = 1; j <= i; j ++)//1.求阶乘
    //2.再乘上阶乘
}
//3.求末尾零的个数

时间复杂度:\(O(n^2)\)

\(n\le10^8\)

小A、小B: 不用想,肯定超时

回想铺垫知识

\(n! = n\times (n - 1)!\)

小A: 可以优化成

int s1;
for(int i = 1; i <= n; i ++)
{
    s1 *= i;//1.求阶乘
    //2.再乘上阶乘
}
//3.求末尾零的个数

时间复杂度:\(O(n)\)
时间够了,但是……

\(n\le10^8\)

小A: 换long long啊
小B: emmm,25的阶乘已经超过long long上限了,所以int换long long也没用

我们只能另找方案

正确思路

我们知道末尾零的个数只跟这些数中因数2因数5有关,等于它们俩中的最小值
小B: 因数5总是比因数2少,所以我们只用求因数5的个数即可
小A: 那么每次求出当前的i的因数5的个数加在i的阶乘的因数5的个数中,再加到总数中就行了

所以完整代码是

#include<bits/stdc++.h>
using namespace std;
long long sum5/*答案*/, s5/*当前阶乘中因数5的个数*/;
int main()
{
    int n;
    cin >> n;
    for(int i = 1; i <= n; i ++)
    {
        int ii = i;
        while(ii % 5 == 0)//求因数5的个数
        {
            s5 ++;//每次不清零,继承上一次的
            ii /= 5;
        }
        sum5 += s5;
    }
    cout << sum5;
    return 0;
}

小A、小B: AC啦~


作者:这是我第一次使用小A、小B两个角色,使我的题解更加生动有趣。有时他们有些搞笑,有时却能有很好的思路。希望加入这两个角色会是我的题解更好,更明了。

posted @ 2022-12-10 12:28  yuzihang  阅读(79)  评论(0)    收藏  举报