数论相关知识
1、算数基本定理(唯一分解定理)
1、内容任何一个大于1的自然数 ,如果N不为质数,都可以唯一分解成有限个质数的乘积
,这里
均为质数,其诸指数
是正整数。
2、唯一分解定理具有:
①唯一性(分配方式的唯一性)
②存在性
3、常见应用
- 多重集合的排列数问题
2、操作
-
分解质因数—>优化:筛法求素数(线性筛法)
- 目标:
- 1~n中所有的质数
- 以及每个数的最小质因子
- 目标:
-
代码实现
const int N=100010;
int primes[N],cnt;//存储所有的质数
bool st[N];//判断当前数是否被筛过
int get_peimer(int n)
{
for(int i=2;i<=n;i++)//O(n)
{
if(!st[i]) primes[cnt++]=i;
for(int j=0;primes[i]*i<=n;j++)//从小到大,枚举所有的质数
{
st[i*primes[j]]=true;//筛出最小质因数是primer[j]的所有合数
if(n%primes[j]==0) break;/
}
}
}
int main()
{
get_primes(10000);//筛选1~1000内的所有质数
}
3、优化
- 筛掉的一定是合数,且
- 合数一定能被筛
3、具体应用
-
AcWing 1295. X的因子链
- 输入正整数 X,求 X 的大于 1 的因子组成的满足任意前一项都能整除后一项的严格递增序列的最大长度,以及满足最大长度的序列的个数。
-
算法分析
-
多重集合的排列数问题
-
而关于X的因子链序列的计算便涉及到排列 这是因为不同因子交换顺序便会获得不同的序列
而在此过程中便会产生相同因子的排列情况 通过预处理阶乘便可快速获得阶乘数从而不需要在进行多余计算
-
-
代码实现
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const int N=(1<<20)+10;
int primes[N],cnt;//前i个质数
int minp[N];//当前数的最小质因子
bool st[N];//判断是否被筛
void get_primes(int n)
{
for(int i=2;i<=n;i++)
{
if(!st[i])
{
minp[i]=i;
primes[cnt++]=i;
}
for(int j=0;primes[j]*i<=n;j++)
{
int t=i*primes[j];//筛掉以primes[j] 为最小质因数的合数
st[t]=true;
minp[t]=primes[j] ;
if(i%primes[j]==0) break;
}
}
}
int main()
{
get_primes(N-1);//需要多个输入,所以列举每个的质因数
int sum[N];//质因数个数,
int x;
while(scanf("%d",&x)!=-1)
{
int k=0,tot=0;//记录质因数出现的个数以及总的个数
while(x>1)
{
int p=minp[x];
sum[k]=0;
while(x%p==0)//记录质因数p出现的次数
{
x/=p;
sum[k]++;
tot++;
}
k++;
}
LL res=1;
for(int i=1;i<=tot;i++) res*=i;
for(int i=0;i<k;i++)//出现质因数的=0;i<k;i++)//出现质因数的阶乘
for(int j=1;j<=sum[i];j++)
res/=j;
printf("%d %lld\n",tot,res);
}
return 0;
}