矩阵末尾0的数量

题目描述
给定一个非负整数 NN,返回 N!N! 结果的末尾为 00 的数量。
N!N! 是指自然数 NN 的阶乘,即:N!=123…(N-2)*(N-1)*NN!=1∗2∗3…(N−2)∗(N−1)∗N。

示例2
输入 5
返回值 1 (说明 5!=120 )

求解矩阵末尾0的个数可以看成是求解在阶乘最终结果中可以整除10次数,也可以看成是求解在1~n中有多少个2的倍数记为 p 和 多少个5的倍数记为 q,在 1 ~n中,p > q ,原因如下。
计算p和q的统一公式如下:n/p + n/p2+n/p3+…… 这些指的是整除,下取整。
该公式的含义可以理解为下取整意味着存在一个数 k ,使得 k可以整除p,举个例子,比如 n == 5,5/2 意味着现在我使用到的数字是4和2, 5/4 由于4还包含另一个2,因此现在使用到的数字是4。通俗理解可以结合筛质数的方法(埃式筛质法原理:如果一个数是质数,那么该质数的平方就不是质数,三次方也不是质数,这类数字都必须要筛掉),只不过在本例中计算倍数时需要将这些数字求和。
理解了公式以后对于本题目就只需要求解1~n 中有多少个5的倍数。计算公式就是那行代码,每次循环分子都会在原有基础上除以5,也就是除以平方,三次方这样的含义。

class Solution {
public:
    /**
     * the number of 0
     * @param n long长整型 the number
     * @return long长整型
     */
    long long thenumberof0(long long n) {
        // write code here
        long long res=0;
        while(n!=0)
        {
            res+=n/5,n/=5;
        }
        return res;
    }
};
扩展题目

题目一
给定整数 N,试把阶乘 N! 分解质因数,按照算术基本定理的形式输出分解结果中的 pi 和 ci 即可。
输入格式,一个整数 N。
输出格式,N! 分解质因数后的结果,共若干行,每行一对 pi,ci,表示含有 pcii 项。按照 pi 从小到大的顺序输出。

数据范围:1≤N≤106
示例:
输入样例:
5
输出样例:
2 3
3 1
5 1
样例解释
5!=120=23∗3∗5

该题目可以看作上一个题目的扩展,上一个题目只是求解 1~n 中有多少个5的倍数,这次求解的是在中 1~n 中有多少个数是N!所包含的质因数的倍数,比如样例5!,该数字的质因数是 2 ,3 ,5。分别求解这几个数字在1~n 中有多少个数是这些质因数的倍数。
其次还有个问题就是要求解 5! 所包含的质因数,可以转化为求解 5 以内每个数包含的质数分别是哪些,原因在于 5!=54321 ,乘积之后数字变大,要求解质因数不需要将完整的阶乘算出来再求解。

n = 1e7的时候线性筛质法基本就比埃式筛法快一倍了。

算法核心:n仅会被其最小质因子pj筛掉。

  • 当n为一个合数的时候,如果i比n / pj还小,就一定会被筛掉
  • 判断i%pj ==0,pj一定是i的最小质因子,pj也一定是pj*i最小质因子
  • 判断i%pj != 0,pj一定小于i的所有质因子,pj也一定是pj*i最小质因子
  • 对于一个合数x,假设pj是x的最小质因子,当i枚举到x /pj的时候,一定会被筛掉。
  • for(int j = 0; primes[j] <= n / i; j ++)中注意下是<=。
#include<iostream>
#include<cstring>
using namespace std;
const int N=1000010;

bool st[N];
int cnt=0;
int primes[N];
//线性筛质法
void get_primes(int n)
{
    for(int i=2;i<=n;i++)
    {
        if(!st[i]) primes[cnt++]=i;
        for(int j=0;primes[j]<=n/i;j++)
        {
            st[primes[j]*i]=true;
            if(i%primes[j]==0) break;
        }
    }
}
int main()
{
    int n;
    cin>>n;
    get_primes(n);
    for(int i=0;i<cnt;i++)
    {
        int p = primes[i];
        int s=0,t=n;
        while(t) s+=t/p,t/=p;
        printf("%d %d\n",p,s);
    }
    return 0;
}

题目二

leecode 793

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值