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正因子個數為$(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
遞推公式:
// 動態規划
#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;
}
