一.定理内容
任何一个大于1的自然数 N,如果N不为质数,那么N可以唯一分解成有限个质数的乘积N=P1^a1*P2^a2*P3^a3*......*Pn^an,这里P1<P2<P3......<Pn均为质数,其中指数ai是正整数。这样的分解称为 N 的标准分解式。
性质:每个大于1的自然数N(非质数)均可以被分解且他们的分解形式是唯一的。
二.代码
(1)素数打表后分解
代码1:遍历所有素数,若有素数因子,则除尽该因子后继续遍历,直到该数字变为1
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
const int maxn = 10000 + 7;
int prime[maxn],len,n,num;
int p[maxn],q[maxn];
bool judge[maxn];
void isPrime(){//素数打表
len = 0;
memset(judge,0,sizeof(judge));
judge[1] = 1;
for(int i = 2;i<=maxn;i++){
if(!judge[i])prime[len++] = i;
for(int j = 0;j<len;j++){
if(i*prime[j]>maxn)break;
judge[i*prime[j]] = 1;
if(i%prime[j]==0)break;
}
}
}
void Split(int k){//分解
memset(p,0,sizeof(p));
memset(q,0,sizeof(q));
for(int i = 0;i<len;i++){
while(k%prime[i]==0){
if(!p[num])p[num] = prime[i];
q[num]++;
k/=prime[i];
}
if(p[num])num++;
if(k==1)break;//退出条件是变为1
}
}
int main()
{
isPrime();
while(scanf("%d",&n)!=EOF){
num = 0;
Split(n);
printf("%d = ",n);
for(int i = 0;i<num;i++){
if(i!=0)printf("*");
printf("%d^%d",p[i],q[i]);
}
printf("\n");
}
return 0;
}
代码二:根据求因子条件,素数只枚举到prime[i]*prime[i]<=n , 最后若n>1就说明还剩下一个一次方的素数
原因:
若n%prime[i]==0,则n = prime[i] * q , 然后我们把n里面的prime[i]因子除尽以后,n = 1*k , n就变成了一个新的数字,因为我们的素数枚举是从小到大的,小的除尽了,如果k是一个合数,那么肯定能拆成素数乘积,而且这个素数是肯定>prime[i]的,也一定满足prime[j]*prime[j] <=n是能继续拆的;另一方面,如果只剩下一个素数,就不会满足prime[j]*prime[j]<=n了,所以这种方法是可行的。
void Split(int k){
memset(p,0,sizeof(p));
memset(q,0,sizeof(q));
for(int i = 0;i<len&&prime[i]*prime[i]<=k;i++){//判断条件变化
while(k%prime[i]==0){
if(!p[num])p[num] = prime[i];
q[num]++;
k/=prime[i];
}
if(p[num])num++;
}
if(k>1){p[num] = k;q[num++]++;}//结尾判断
}
(2)直接分解法(不用素数打表)
void Split(int k){
memset(p,0,sizeof(p));
memset(q,0,sizeof(q));
for(int i = 2;i*i<=k;i++){
while(k%i==0){
if(!p[num])p[num] = i;
q[num]++;
k/=i;
}
if(p[num])num++;
}
if(k>1){p[num] = k;q[num++]++;}
}
三.应用
(1)欧拉函数求互质:欧拉函数
(2)化大数运算为小数运算 例UVA - 10375
组合数运算,优先考虑取模,但是此处直接运算没有取模,而且数量很大,因为保证输出结果不超过10^8,所以可以看出,结果不大但是中间运算过程中的乘阶会很大。
方法一:因为组合数分子与分母数量一致,我们直接乘一个,除一个。
方法二:利用唯一分解定理,把所有的数,拆分为小的素数,然后统一计算所有素数的乘积
代码:
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 10000 + 7;
int prime[maxn],er[maxn],len;
int p,q,r,s;
bool judge[maxn];
void isPrime(){//筛素数
memset(judge,0,sizeof(judge));
judge[1] = 1;
len = 0;
for(int i = 2;i<maxn;i++){
if(!judge[i])prime[len++] = i;
for(int j = 0;j<len;j++){
if(i*prime[j]>=maxn)break;
judge[i*prime[j]] = 1;
if(i%prime[j]==0)break;
}
}
}
void addPrime(int n,int d){
int ans = n;
for(int i = 0;i<len;i++){//分解
while(ans%prime[i]==0){
er[i]+=d;//er保留所有素数的指数
ans/=prime[i];
}
if(ans==1)break;
}
}
void addMultiply(int n,int d){//(N!)^d
for(int i = 2;i<=n;i++){
addPrime(i,d);
}
}
int main()
{
isPrime();
while(scanf("%d%d%d%d",&p,&q,&r,&s)!=EOF){
memset(er,0,sizeof(er));
addMultiply(p,1);
addMultiply(q,-1);
addMultiply(p-q,-1);
addMultiply(r,-1);
addMultiply(s,1);
addMultiply(r-s,1);
double num = 1;
for(int i = 0;i<len;i++){
num*=pow(prime[i],er[i]);
}
printf("%.5lf\n",num);
}
return 0;
}