数学专题2----求因子数(唯一分解定理)

唯一分解定理:

任何一个大于1的自然数 N,如果N不为质数,那么N可以唯一分解成有限个质数的乘积N=P1a1P2a2P3a3......Pnan,这里P1<P2<P3......<Pn均为质数,其中指数ai是正整数。这样的分解称为 N 的标准分解式

大概意思就是说可把一个数写成素数乘积的形式,例如:

12= 2^2 * 3^1 , 42= 2^1 * 3^1 * 7^1 , 18= 2^1 * 3^2 ........等等;

所以就必须要用到素数筛,不会欧拉筛(线性筛)的可以先去网上学一下。

·素数筛:

代码:

void get_pr()
{
	for(int i=2;i<=N;i++)
	{
		if(!st[i])pr[len++]=i;
		for(int j=0;j<len&&pr[j]<=N/i;j++)
		{
			st[pr[j]*i]=1;
			if(i%pr[j]==0)break;
		}
	}
}

 注意事项:

素数数组一般不开到1e7,状态标记数组一般要开大一些,防止数组越界。

·求因子总数:

原理很简单,就是遍历从最小的素数开始除,记录每个素因子的个数,因为这里不需要求每一个质因子,所以就不开数组存了,直接记录完每一个素数个数直接运算........

代码:

int geta_1(ll n)
{
	int ans=1;
	for(int i=0;i<len&&pr[i]*pr[i]<=n;i++)
	{
		int x=0;
		while(n%pr[i]==0)
		{
			n=n/pr[i];
			x++;
		}
		ans*=(x+1);
	}
	if(n>1)ans*=2;
	return ans;
}

配合素数筛使用即可。

完整代码:

#include<iostream>
using namespace std;
typedef long long ll;
const int N=1e6;
int pr[N],st[N*5],len=0;
void get_pr()
{
	for(int i=2;i<=N;i++)
	{
		if(!st[i])pr[len++]=i;
		for(int j=0;j<len&&pr[j]<=N/i;j++)
		{
			st[pr[j]*i]=1;
			if(i%pr[j]==0)break;
		}
	}
}
ll geta(ll n)
{
	ll ans=1;
	for(ll i=0;i<len&&pr[i]*pr[i]<=n;i++)
	{
		ll x=0;
		while(n%pr[i]==0)
		{
			x++;
			n=n/pr[i];
		}
		ans=ans*(x+1);
	}
	if(n>1)ans*=2;
	return ans;
}
int main()
{
	get_pr();
	int t;
	cin>>t;
	while(t--)
	{
		ll n;
		cin>>n;
		printf("%lld\n",geta(n));
	}
	return 0;
}

 质因子分解(求每个质因子的个数):

原理和上面的一样,只是开了一个数组存一下,这里结合洛谷上的一个题来将来讲。

·例题:

P2043 质因子分解

题目描述

对 N! 进行质因子分解。

输入格式

输入数据仅有一行包含一个正整数 N,N≤10000。

输出格式

输出数据包含若干行,每行两个正整数 p,a,中间用一个空格隔开。表示 N! 包含 a 个质因子 p,要求按 p 的值从小到大输出。

输入输出样例

输入 

10

输出 

2 8
3 4
5 2
7 1

说明/提示

10!=3628800=(28)×(34)×(52)×710!=3628800=(28)×(34)×(52)×7。

·分析:

因为阶乘的数非常大,先算阶乘再求答案显然不可能,那就把阶乘拆开来算

代码:

#include<iostream>
using namespace std;
typedef long long ll;
const int N=1e6;
int pr[N],st[N*2],len=0,f[N];
void get_pr()
{
	for(int i=2;i<=N;i++)
	{
		if(!st[i])pr[len++]=i;
		for(int j=0;j<len&&pr[j]<=N/i;j++)
		{
			st[pr[j]*i]=1;
			if(i%pr[j]==0)break;
		}
	}
}
void geta(int n)
{
	for(int i=0;i<len&&pr[i]*pr[i]<=n;i++)
	{
		while(n%pr[i]==0)
		{
			n=n/pr[i];
			f[pr[i]]++;
		}
	}
	if(n>1)f[n]++;
}
int main()
{
	get_pr();
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)geta(i);
	for(int i=0;i<len;i++)
	{
		if(f[pr[i]]>0)
		{
			printf("%d %d\n",pr[i],f[pr[i]]);
		}
	}
	return 0;
}

 小结:

当然肯定还有其他方法,我这里是用桶排数组的思想直接存个数,因为这里素数不会特别大所以刚好合适,其实也可以存素数的下标,不过这里不需要。

总结:

唯一分解定理应用还是非常广泛的,所以还是有必要掌握的。对于我这个不是数学专业的人来说,一切的数学公式和定理都不过是解决问题的工具,不必深究原理,目的只有一个,能解决问题就行。

!~~~小趴菜努力学习中ing........

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值