牛客网 阶乘分解 (数学)

题目描述:

给定整数 N(1≤N≤106),试把阶乘 N! 分解质因数,按照算术基本定理的形式输出分解结果中的 P i P_i Pi C i C_i Ci 即可。
输入描述:
一个整数N。
输出描述:
N! 分解质因数后的结果,共若干行,每行一对 P i P_i Pi, C i C_i Ci​,表示含有 P i C i P_i^{C_i} PiCi​​项。按照 P i P_i Pi从小到大的顺序输出。
示例1
输入
5
输出
2 3
3 1
5 1
说明
5!=120=23 *3*5
题目链接:https://ac.nowcoder.com/acm/contest/1021/B
来源:牛客网

80分暴力解法:

1.因为N!=1*2*3*…*(N-1)*N,所以N!的质因子必然小于N。故只需要用线性筛获得[1,N]之间的素数表。不会素数线性筛的看这里->素数线性筛
2.对N的阶乘进行质因数分解转化为对[1,N]的每一个数进行质因数分解再将相同质因子的指数数累加即可。
3.依次用素数表中的质数对[2,N]区间的数i进行“试除”,直到i中不含质因子。

#include<cstdio>
const int maxn=1e6+20;
int vis[maxn];
int primes[maxn];   / /素数表
int counts[maxn];  / /统计素数个数,counts[i]表示primes[i]的个数
void get_primes(int n){
    
      / /线性素数筛获得素数表
int cnt=0;  
for(int i=2;i<=n;i++){
    
    
if(vis[i]==0){
    
    primes[cnt]=i;cnt++;}   
 for(int j=0;j<cnt;j++){
    
    
 if(i*primes[j]>n) break;
 vis[i*primes[j]]=1;
 if(i%primes[j]==0) break;   
 }      
}   
}
int main(){
    
    
int N;
scanf("%d",&N);
get_primes(N);
for(int i=2;i<=N;i++){
    
    
int t=i;     
int cnt=0;   
while(t>1){
    
     / /注意t为1的时候就没有质因子了 
if(t%primes[cnt]==0){
    
     / /primes[cnt]是当前i(用t先代替)的质因子,则统计次数,并将i除去因子primes[i]
counts[cnt]++;
t=t/primes[cnt];
}
else cnt++; / /primes[cnt]不是当前i 的因子,则换另一个质数试探   
}
}
int i=0; 
while(counts[i]>=1){
    
     / /输出素数及对应的个数
printf("%d %d\n",primes[i],counts[i]);    
i++;  
}   
return 0;   
}

以上代码中的“试除”部分效率过低,无法AC。

正解

其实此处涉及到一个数论知识:

  • N!中质因子p的个数为: ⌊ N p ⌋ \lfloor{\frac{N}{p}}\rfloor pN+ ⌊ N p 2 ⌋ \lfloor{\frac{N}{p^2}}\rfloor p2N+ ⌊ N p 3 ⌋ \lfloor{\frac{N}{p^3}}\rfloor p3N+…+ ⌊ N p ⌊ log ⁡ N P ⌋ ⌋ \lfloor{\frac{N}{p\lfloor{\log_N P}\rfloor}}\rfloor plogNPN。即1~N之间的数中含有因子p的数有 ⌊ N p ⌋ \lfloor{\frac{N}{p}}\rfloor pN个,含有因子p2的数有 ⌊ N p 2 ⌋ \lfloor{\frac{N}{p^2}}\rfloor p2N
  • 注意: ⌊ N p i ⌋ \lfloor{\frac{N}{p^i}}\rfloor piN指的是1~N中含有因子 p i p^i pi的数的个数,例如N=10、p=2时, ⌊ N p ⌋ \lfloor{\frac{N}{p}}\rfloor pN= ⌊ 10 2 ⌋ \lfloor{\frac{10}{2}}\rfloor 210=5,即 1~10之间含有因子2的数有5个:2、4、6、8、10。 ⌊ N p 2 ⌋ \lfloor{\frac{N}{p^2}}\rfloor p2N= ⌊ 10 4 ⌋ \lfloor{\frac{10}{4}}\rfloor 410=2,含有4为因子的数有2个:4、8。
  • 一张可能有助于理解的图:
    在这里插入图片描述

AC代码:

/ /AC代码:
#include<cstdio>
const int maxn=1e6+20;
int vis[maxn];
int primes[maxn];
int get_primes(int n){
    
    / /得到1~N之间的素数表,并返回素数个数
int cnt=0;
for(int i=2;i<=n;i++){
    
    
if(vis[i]==0){
    
    primes[cnt]=i;cnt++;}    
 for(int j=0;j<cnt;j++){
    
    
 if(i*primes[j]>n) break;
 vis[i*primes[j]]=1;    
 if(i%primes[j]==0) break; 
 }       
 }
return  cnt;
}
int main(){
    
    
int N;
scanf("%d",&N);
int cnt=get_primes(N);
for(int i=0;i<cnt;i++){
    
     
int p=primes[i],n=N,c=0; / /用c统计当前质数P的个数
while(n){
    
      / /直到n/p为0,即n除p向下取整为0
 c+=n/p;   
 n=n/p;    
}
if(c!=0) printf("%d %d\n",primes[i],c);    
} 
return 0;    
}

猜你喜欢

转载自blog.csdn.net/IAMLSL/article/details/108061694