阶乘中末尾0的个数和及其扩展--记一道牛客小白月赛题

题目描述

题目链接

1 ! 2 ! n ! 中末尾0的个数。

分析

首先需要解决的是 n ! 末尾0 的个数,我们记 :

f ( n ) : n ! 中末尾0 的个数

那么原问题就变成了: a n s = i = 1 n f ( i ) , 记 S ( n ) = i = 1 n f ( i )

我们接下来求阶乘末尾0的个数,即 f ( n )

求解 f ( n )

由于2*5的乘积就会产生一个0,而且5的倍数比2的倍数少,所以只需统计5的倍数的个数,这就是0的个数,

n ! = 5 5 2 5 3 5 k a i

其中 a i 不整除 5。那么显然, k = n / 5 的下整,同时 n ! = 5 k 1 2 3 k a i , 所以有

f ( n ) = k + f ( k )

时间复杂度 O ( l o g N )

扫描二维码关注公众号,回复: 2349315 查看本文章

求解 S ( n )

由于

f ( 5 k ) = k + f ( k )
f ( 5 k + 1 ) = k + f ( k )

f ( 5 k + 4 ) = k + f ( k )

全部累加,可得

S ( 5 k + 4 ) = i = 1 k 5 ( i + f ( i ) ) = 5 ( k + 1 ) k 2 + S ( k )

每次找到一个最大的k,使得 5 k + 4 n , 剩余的项直接计算就好,因此总的时间复杂度

时间复杂度 O ( l o g 2 N )

code

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

#define MAXN 1000010

typedef unsigned long long uLL;
typedef long long LL;

uLL n;

uLL f(uLL k){
    if(k< 5)return 0;
    else return k/5 + f(k/5);
}
uLL S(uLL k){
    uLL ret =0;
    if(k < 5){
        for(uLL i=1 ; i<=k ; ++i)
            ret+= f(i);
        return ret;
    }else{
        uLL t = k/5;
        for(uLL i = 5*t; i <=k ; ++i) ret += f(i);
        ret+= 5*(t-1)*t/2;
        return ret+5*S(t-1);
    }
}

int main(int argc, char const *argv[]) {
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cin>>n;
    std::cout << S(n) << '\n';
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Dylan_Frank/article/details/81166799
今日推荐