阶乘分解(暴力+卡常)

题目来源:牛客网

链接:https://ac.nowcoder.com/acm/contest/1021/B

题目描述

给定整数 N(1≤N≤10^6)(1≤N≤10^6)(1≤N≤10^6),试把阶乘 N! 分解质因数,按照算术基本定理的形式输出分解结果中的pi和 ci​ 即可。

输入描述:

一个整数N。

输出描述:

N! 分解质因数后的结果,共若干行,每行一对pi,ci​,表示含有pi^ci​​项。按照pi从小到大的顺序输出。

示例1:

输入:

5

输出:

2 3
3 1
5 1

说明

5!=120=23∗3∗5

———————————————————————————————————————————

正解:先用线性筛素数筛出a以内的素数,对于任意一个素数p,p在a!中出现的次数为[\frac{a}{p}]+[\frac{a}{p^{^{2}}}]+...+[\frac{a}{p^{^{k}}}]

其中p^k<=a。

Code:

#include<bits/stdc++.h>
using namespace std;
const int N=1000010;
int p[N],st[N],cnt;
int main()
{
    int n;
    cin>>n;
    /*线性筛素数*/
    for(int i=2;i<=n;i++){
        if(!st[i]) p[cnt++]=i;
        for(int j=0;p[j]<=n/i;j++){
            st[i*p[j]]=1;
            if(i%p[j]==0) break;
        }
    }
    for(int i=0;i<cnt;i++){
        int k=0;
        long long a=p[i]; //注意到5次方量级就会爆int
        while(a<=n){
            k+=n/a;
            a*=p[i];
        }
        printf("%d %d\n",p[i],k);
    }
    return 0;
}

运行结果:

 还是很快的。

下面介绍暴力的方法。

如果没学过线性筛法的同学,可以直接考虑对1-n每个数进行质因数分解,简单粗暴。

代码如下:

#include<bits/stdc++.h>
using namespace std;
int p[1000010];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=2;i<=n;i++){
        int k=i;
        for(int j=2;j<=k/j;j++)
            while(k%j==0) k/=j,p[j]++;
        if(k>1) p[k]++;
    }
    for(int i=2;i<=n;i++)
        if(p[i]) printf("%d %d\n",i,p[i]);
    return 0;
}

以上代码提交上去会TLE,运行时间1s多一点,本题时间限制为1s.

用快读快写卡常。(原理是putchar和getchar比较快)

#pragma GCC optimize(2)
#include<stdio.h>
int p[1000010];
inline int Read() //快读
{
    int x=0,f=1;char c=getchar();
    while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') {x=x*10+c-'0'; c=getchar();}
    return x*f;
}
inline void out(int x) //快写
{
    if(x>=10){
        out(x/10);
    }
    putchar(x%10+'0');
}
int main()
{
    int n=Read();
    for(int i=2;i<=n;++i){
        int k=i;
        for(int j=2;j<=k/j;++j)
            while(k%j==0) k/=j,++p[j];
        if(k>1) ++p[k];
    }
    for(int i=2;i<=n;++i)
        if(p[i]){
        	out(i),putchar(' '),out(p[i]),putchar('\n');
		}
    return 0;
}

运行结果:

 优化了60ms左右,时间有点紧,如果数据量再大一点就不行了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值