题目大意
给定整数 N N N ,试把阶乘 N ! N! N! 分解质因数,按照算术基本定理的形式输出分解结果中的 p i p_i pi和 c i c_i ci即可。
分析-法一 LUOGU可过
这道题最容易想到的就是循环
[
1
,
n
]
[1,n]
[1,n]这个区间,把每个数用来分解质因数,把分解的结果存进ans
数组里面,依次相加,最后得到结果输出;
分解质因数的算法比较常见,这里采用的是 O ( n ) O(\sqrt{n}) O(n)的写法,不再赘述;
但是数据范围有差异!
LUOGU
1
≤
n
≤
1
0
5
1 \le n \le 10^5
1≤n≤105 AC 100pts
NKOJ
1
≤
n
≤
1
0
6
1 \le n \le 10^6
1≤n≤106 TLE 80pts
Code(LUOGU)
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,a[1000005];
void nkrq008_is_sb(int k){
for(int j=2;j*j<=k;j++){
while(k%j==0){
k/=j;a[j]++;
}
}
if(k>1){a[k]++;}
return;
}
signed main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++){
nkrq008_is_sb(i);
}
for(int i=1;i<=1000000;i++){
if(a[i]!=0){
printf("%lld %lld\n",i,a[i]);
}
}
return 0;
}
分析-法二(更优解,双OJ均可过)
经过分析,我们会发现值为 p i p_i pi的质因子他在 N ! N! N!存在的个数有: ⌊ n p i 1 ⌋ + ⌊ n p i 2 ⌋ + ⌊ n p i 3 ⌋ + . . . . . . + ⌊ n p i k ⌋ \left \lfloor \frac{n}{p_i^1} \right \rfloor +\left \lfloor \frac{n}{p_i^2} \right \rfloor+\left \lfloor \frac{n}{p_i^3} \right \rfloor +......+\left \lfloor \frac{n}{p_i^k} \right \rfloor ⌊pi1n⌋+⌊pi2n⌋+⌊pi3n⌋+......+⌊pikn⌋
为什么,因为是 p i p_i pi的倍数的数每隔 p i p_i pi个数出现一次,是 p i 2 p_i^2 pi2的倍数的数每隔 p i 2 p_i^2 pi2个数出现一次,以此类推,直到 ⌊ n p i k ⌋ \left \lfloor \frac{n}{p_i^k} \right \rfloor ⌊pikn⌋的值为 0 0 0时结束;
这就好办了,开始一个埃筛筛出 n \sqrt{n} n里面的所有质数,然后用上述的公式去计算每个质因子出现的个数( p i ≤ n p_i \le n pi≤n),最后相加输出即可;
AC Code
#include<bits/stdc++.h>
#define int long long
#pragma GCC optimize(2)
using namespace std;
int n,a[1000005],vis[1000005];
void nkrq008_is_sb(int k){
for(int i=2;i*i<=k;i++){
if(!vis[i]){
for(int j=i*i;j<=k;j+=i){
vis[j]=1;
}
}
}
return;
}
signed main(){
scanf("%lld",&n);
nkrq008_is_sb(n);
for(int i=2;i<=n;i++){
if(!vis[i]){
int num=i;
while((n/num)>=1){
a[i]+=(n/num);
num*=i;
}
}
}
for(int i=1;i<=n;i++){
if(a[i]){
printf("%lld %lld\n",i,a[i]);
}
}
return 0;
}