整数因子分解问题(递归分治法、动态规划)
整数因子分解问题(递归分治法、动态规划)
Description
大于1的正整数n可以分解为:n=x1 * x2 * … * xm。 例如,当n=12 时,共有8 种不同的分解式: 12=12; 12=6 * 2; 12=4 * 3; 12=3 * 4; 12=3 * 2 * 2; 12=2 * 6; 12=2 * 3 * 2; 12=2 * 2 * 3。 对于给定的正整数n,计算n共有多少种不同的分解式。
Input
输入数据只有一行,有1个正整数n (1≤n≤2000000000)。
Output
将计算出的不同的分解式数输出。
Sample Input
12
1
Sample Output
8
1
递归分治法:
耗时有些大,但是通过了。
f ( n ) f(n)f(n) 为n的不同分解式个数。
f ( n ) = ∑ n % i = = 0 f ( n / i ) , 2 < = i < = n f(n) = \sum_{n\%i==0} f(n/i),\\ 2 <= i <= nf(n)=∑
n%i==0
f(n/i),
2<=i<=n
比如20
f ( 1 ) = 1 f(1) = 1f(1)=1
f ( 20 ) = f ( 2 ) + f ( 10 ) + f ( 4 ) + f ( 5 ) + f ( 1 ) f(20) = f(2) + f(10) + f(4) + f(5) + f(1)f(20)=f(2)+f(10)+f(4)+f(5)+f(1)
f ( 2 ) = f ( 1 ) = 1 f(2) = f(1) = 1f(2)=f(1)=1
f ( 10 ) = f ( 2 ) + f ( 5 ) + f ( 1 ) = 1 + 1 + 1 = 3 f(10) = f(2) + f(5) + f(1) = 1 + 1 + 1 = 3f(10)=f(2)+f(5)+f(1)=1+1+1=3
f ( 4 ) = f ( 2 ) + f ( 1 ) = 1 + 1 = 2 f(4) = f(2) + f(1) = 1 + 1 = 2f(4)=f(2)+f(1)=1+1=2
f ( 5 ) = f ( 1 ) = 1 f(5) = f(1) = 1f(5)=f(1)=1
所以:f ( 20 ) = 1 + 3 + 2 + 1 + 1 = 8 f(20) = 1 + 3 + 2 + 1 + 1 = 8f(20)=1+3+2+1+1=8
发现f ( n ) 里 会 有 f ( n / n ) f(n)里会有f(n/n)f(n)里会有f(n/n),所以f ( n ) f(n)f(n)初始值可以初始化为1
for循环找因子也不用一直到n,到sqrt(n)就行,也就是i * i < n就行
最后判断一下i * i == n,因为左右因子都一样怎么交换都一样,所以只用加上f ( i ) f(i)f(i)即可
比如f ( 100 ) = f ( 2 ) + f ( 50 ) + f ( 4 ) + f ( 25 ) + f ( 5 ) + f ( 20 ) + f ( 10 ) + f ( 1 ) f(100) = f(2) + f(50) + f(4) + f(25) + f(5) + f(20) + f(10) + f(1)f(100)=f(2)+f(50)+f(4)+f(25)+f(5)+f(20)+f(10)+f(1)
i * i < n,f ( n ) = ∑ n % i = = 0 ( f ( n / i ) + f ( i ) ) f(n) = \sum_{n \% i == 0} (f(n / i) + f(i))f(n)=∑
n%i==0
(f(n/i)+f(i))
i * i == n,f ( n ) = f ( n ) + f ( i ) f(n) = f(n) + f(i)f(n)=f(n)+f(i)
比如f ( 20 ) = f ( 2 ) + f ( 10 ) + f ( 4 ) + f ( 5 ) + f ( 1 ) f(20) = f(2) + f(10) + f(4) + f(5) + f(1)f(20)=f(2)+f(10)+f(4)+f(5)+f(1)
找出f ( 2 ) f(2)f(2)就可以加上f ( 20 / 2 ) = f ( 10 ) f(20 / 2) = f(10)f(20/2)=f(10),f ( 4 ) f(4)f(4)可以得f ( 20 / 4 ) = f ( 5 ) f(20/4) = f(5)f(20/4)=f(5)
// 递归法
#include <stdio.h>
int solve(int n)
{
int ans = 1, i; // ans = 1初始表示n = n的情况
for (i = 2; i * i < n; i++) // 因子乘因子小于n
if (n % i == 0) // i 是 n的因子, n / i也是n的因子
ans += solve(i) + solve(n / i);
if (i * i == n) // i是n的因子, 并且i * i == n时只有这一种情况, 左右交换也是一种
ans += solve(i);
return ans;
}
int main()
{
int n;
scanf("%d", &n);
printf("%d\n", solve(n));
return 0;
}
动态规划法:
算术基本定理:任何一个大于1的自然数N,如果N不为质数,那么N可以唯一分解成有限个质数的乘积
N = p 1 x 1 ∗ p 2 x 2 ∗ . . . ∗ p n x n p 1 , p 2 , . . . , p n 都 为 质 数 x 1 , x 2 , . . . , x n 都 是 大 于 等 于 0 的 整 数 N = p_1^{x_1} * p_2^{x_2} * ...*p_n^{x_n} \\ p_1, p_2,\ ...\ ,p_n都为质数 \\ x_1, x_2,\ ...\ ,x_n都是大于等于0的整数
N=p
1
x
1
∗p
2
x
2
∗...∗p
n
x
n
p
1
,p
2
, ... ,p
n
都为质数
x
1
,x
2
, ... ,x
n
都是大于等于0的整数
可以得出:
N正因子个数为( x 1 + 1 ) ∗ ( x 2 + 1 ) ∗ . . . ∗ ( x n + 1 ) (x_1 + 1) * (x_2 + 1) * ... * (x_n + 1)(x
1
+1)∗(x
2
+1)∗...∗(x
n
+1)
2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23 * 29 = 6469693230
6469693230的正因子个数为:210 = 1024 , 所以存因子的数组开2000就差不多了
dp[i]存的是factor[i]的分解式个数
一个数可以分解为因子乘积,因子的因子也是因子
所以一个数的分解式个数等于因子的分解式个数之和
dp[]初始化0
递推公式:
d p [ i ] = { 1 i = 0 ∑ j = 0 , f a c t o r [ i ] % f a c t o r [ j ] = = 0 i − 1 d p [ j ] i > = 1 dp[i] =
{1∑i−1j=0,factor[i]%factor[j]==0dp[j] i=0 i>=1
{
1
�
=
0
∑
�
=
0
,
�
�
�
�
�
�
[
�
]
%
�
�
�
�
�
�
[
�
]
==
0
�
−
1
�
�
[
�
]
�
>=
1
dp[i]={
1
∑
j=0,factor[i]%factor[j]==0
i−1
dp[j]
i=0
i>=1
// 动态规划
#include <iostream>
#include <algorithm>
using namespace std;
int solve(int n)
{
// factor数组存因子, dp数组存分解式个数, cnt记录因子个数
int factor[2000], dp[2000], cnt = 0, i;
// 找出n的因子
for (i = 1; i * i < n; i++) // 循环次数缩减到sqrt(n)
{
if (n % i == 0)
{
factor[cnt++] = i; // i为因子
factor[cnt++] = n / i; // n/i也为因子
}
}
if (i * i == n)
factor[cnt++] = i; // 如果i*i==n, i也为因子
sort(factor, factor + cnt); // 把因子从小到大排序
fill(dp, dp + cnt, 0); // 把dp数组初始化为0, 初始因子分解式个数都为0
dp[0] = 1; // 第一个因子(1)自己的分解式只有一个
for (i = 1; i < cnt; i++) // 从第二个因子开始, 循环找第i个因子的因子是否为前i-1个因子
for (int j = 0; j < i; j++)
if (factor[i] % factor[j] == 0) // 如果第i个因子的因子是前i-1个因子中的, 第i个的分解式个数加上满足条件的
dp[i] += dp[j];
return dp[cnt - 1]; // dp[0]从0开始, cnt要减1
}
int main()
{
ios::sync_with_stdio(false); // 防止TLE
cin.tie(NULL);
cout.tie(NULL);
int n;
cin >> n;
cout << solve(n);
return 0;
}
————————————————
版权声明:本文为CSDN博主「yanhua_tj」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_42898536/article/details/109523993
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
2015-10-24 AI顶级会议以及期刊