题目大意
给出一个数
n
n
n,
求约数个数为
n
n
n的最小的那个数。
时间限制
1s
数据范围
n
≤
1
0
3
n\le10^3
n≤103
题目保证答案
≤
1
0
18
\le10^{18}
≤1018
题解
考虑如何计算一个数的约数个数,
假设这个数为
p
1
k
1
×
p
2
k
2
×
⋯
×
p
m
k
m
p_1^{k_1}\times p_2^{k_2}\times\cdots\times p_m^{k_m}
p1k1×p2k2×⋯×pmkm,则它的约数个数就为
Π
i
=
1
m
(
k
i
+
1
)
\displaystyle\Pi_{i=1}^m \pod{k_i+1}
Πi=1m(ki+1)
因此,可以通过考虑质因数的方法来求出满足题意最小的数。
通过简单的计算可以知道,质因数的个数最多可能是
15
15
15个。
不妨设状态 f i , j f_{i,j} fi,j表示利用前 i i i个质数,构造出来约数个数为 j j j的最小的数是多少。
转移也很显然: f i , j = ∑ k = 0 m i n ( f i − 1 , j k + 1 × p i k ) f_{i,j}=\displaystyle\sum_{k=0} min \pod{f_{i-1,\frac{j}{k+1}} \times p_i^k} fi,j=k=0∑min(fi−1,k+1j×pik)
Code
``cpp
//#pragma GCC optimize (2)
//#pragma G++ optimize (2)
#include
#include
#include
#include
#include
#include
#include
#define G getchar
#define ll long long
using namespace std;
int read()
{
char ch;
for(ch = G();(ch < ‘0’ || ch > ‘9’) && ch != ‘-’;ch = G());
int n = 0 , w;
if (ch == ‘-’)
{
w = -1;
ch = G();
} else w = 1;
for(;‘0’ <= ch && ch <= ‘9’;ch = G())n = (n<<1)+(n<<3)+ch-48;
return n * w;
}
const ll N = 1000000000000000000;
int n , tmp , m;
int prime[16] = {0 , 2 , 3 , 5 , 7 , 11 ,13 , 17 , 19 , 23 , 29 , 31 , 37 , 41 , 43 , 47};
ll f[20][1003] , z[100] , ans;
int main()
{
//freopen(“l.in”,“r”,stdin);
//freopen(“l.out”,“w”,stdout);
n = read();
memset(f , 127 , sizeof(f));
f[0][1] = 1;
ans = N;
for (int i = 1 ; i <= 15 ; i++)
{
f[0][1] = 1;
z[0] = 1;
m = 0;
for (int j = 1 ; z[j - 1] <= N / prime[i] ; j++)
{
z[j] = z[j - 1] * prime[i];
m++;
}
for (int j = 2 ; j <= n ; j++)
for (int k = 1 ; k <= m ; k++)
if (j % (k + 1) == 0)
{
tmp = j / (k + 1);
if (f[i - 1][tmp] <= N / z[k]) f[i][j] = min(f[i - 1][tmp] * z[k] , f[i][j]);
}
ans = min(ans , f[i][n]);
}
if(n == 1) puts("1"); else printf("%lld\n", ans);
return 0;
}