题目链接:
题目大意:
给出一个n,问最小的约数个数为n的数是多少。
题目分析:
- 作为一个懒人,看见这种数打不能取模的就喜欢用java水
- 首先能够想到为了保证最小,最多也就用到17个质因数,因为这17个质因数的积已经超过了1e8,所以我们可以枚举这17个质因数出现的次数。
- 然后定义状态dp[i][j]表示前i个质因数组成的因数个数为j个的最小的数。
- 转移方程很简单: dp[i][j∗k]=min{dp[i−1][j]⋅prime[i]k}
- 复杂度O(18⋅n2)
AC代码:
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
static final int MAX = 1007;
static BigInteger []a =
{BigInteger.ZERO,BigInteger.valueOf(2),BigInteger.valueOf(3),BigInteger.valueOf(5),
BigInteger.valueOf(7),BigInteger.valueOf(11),BigInteger.valueOf(13),
BigInteger.valueOf(17),BigInteger.valueOf(19),BigInteger.valueOf(23),
BigInteger.valueOf(29),BigInteger.valueOf(31),BigInteger.valueOf(37),
BigInteger.valueOf(41),BigInteger.valueOf(43),BigInteger.valueOf(47),
BigInteger.valueOf(53),BigInteger.valueOf(59)};
static BigInteger [][]pp = new BigInteger[MAX][MAX];
static BigInteger [][]dp = new BigInteger[MAX][MAX];
static boolean [][]mark = new boolean[MAX][MAX];
public static void main ( String[] args )
{
Scanner cin = new Scanner ( System.in );
int n;
for ( int i = 1 ; i < 18 ; i++ )
{
pp[i][0] = BigInteger.ONE;
for ( int j = 1 ; j < MAX ; j++ )
pp[i][j] = pp[i][j-1].multiply( a[i] );
}
while ( cin.hasNext())
{
n = cin.nextInt();
dp[0][1] = BigInteger.ONE;
for ( int i = 0 ; i < MAX ; i++ )
for ( int j = 0 ; j < MAX ; j++ )
mark[i][j] = false;
mark[0][1] = true;
for ( int i = 1 ; i < 18 ; i++ )
for ( int j = 1 ; j <= n ; j++ )
{
for ( int k = 1; k <= n ; k++ )
{
if ( j*k > n ) continue;
if ( !mark[i-1][j]) continue;
if (!mark[i][j*k] || (dp[i-1][j].multiply(pp[i][k-1])).compareTo(dp[i][j*k])< 0 )
{
dp[i][j*k] = dp[i-1][j].multiply(pp[i][k-1]);
mark[i][j*k] = true;
}
}
}
System.out.println(dp[17][n] );
}
}
}