整數因子分解問題(遞歸分治法、動態規划)


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

Sample Output

8

下面是AC代碼:

遞歸法:

耗時有些大,但是通過了。

$f(n)$ 為n的不同分解式個數。

$f(n) = \sum_{n\%i==0} f(n/i),\\ 2 <= i <= n$

比如20

$f(1) = 1$

$f(20) = f(2) + f(10) + f(4) + f(5) + f(1)$

$f(2) = f(1) = 1$

$f(10) = f(2) + f(5) + f(1) = 1 + 1 + 1 = 3$

$f(4) = f(2) + f(1) = 1 + 1 = 2$

$f(5) = f(1) = 1$

所以:$f(20) = 1 + 3 + 2 + 1 + 1 = 8$

發現$f(n)里會有f(n/n)$,所以$f(n)$初始值可以初始化為1

for循環找因子也不用一直到n,到sqrt(n)就行,也就是i * i < n就行

最后判斷一下i * i == n,因為左右因子都一樣怎么交換都一樣,所以只用加上$f(i)$即可

比如$f(100) = f(2) + f(50) + f(4) + f(25) + f(5) + f(20) + f(10) + f(1)$

i * i < n,$f(n) = \sum_{n \% i == 0} (f(n / i) + f(i))$

i * i == n,$f(n) = f(n) + f(i)$

比如$f(20) = f(2) + f(10) + f(4) + f(5) + f(1)$

找出$f(2)$就可以加上$f(20 / 2) = f(10)$,$f(4)$可以得$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正因子個數為$(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

遞推公式:

$$ dp[i] = \begin{cases} 1 &\ i=0 \\ \sum_{j=0,factor[i] \% factor[j] == 0}^{i-1}dp[j] &\ i>=1 \end{cases} $$
// 動態規划
#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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM