传送门
设
M=a1p1∗a2p2∗......∗anpn
,则因数个数是
Πi=1(pi+1)
然后dp
f[i][j]表示前i个质数,组成了j个因数的最小数字。
+上高精度发现愉快的T了
然后我们可以将数用log的值表示。
到最后再加就可以pass了。
#include<cstring>
#include<cmath>
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#define ll long long
#define mo 1000000000
using namespace std;
const int prime[16]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47};
struct num{
ll a[10005];
void clear(){memset(a,0,sizeof(a));}
void print(){
printf("%lld",a[a[0]]);
for (int i=a[0]-1;i>0;i--) printf("%09lld",a[i]);
printf("\n");
}
num operator * (const num b) const{
num c;
c.clear();
for (int i=1;i<=a[0];i++){
ll x=0;
for (int j=1;j<=b.a[0];j++){
x+=c.a[j+i-1]+a[i]*b.a[j];
c.a[j+i-1]=x%mo;
x/=mo;
}
c.a[i+b.a[0]]=x;
}
c.a[0]=a[0]+b.a[0];
while (!c.a[c.a[0]]&&c.a[0]) c.a[0]--;
return c;
}
}ans,b;
inline void pow(int x,int y,num &p){
num b;
b.clear();
p.clear();
b.a[0]=p.a[0]=p.a[1]=1;
b.a[1]=x;
while (y){
if (y%2) p=p*b;
b=b*b;
y/=2;
}
}
double f[16][50005];
int fa[16][50005],n;
int main(){
scanf("%d",&n);
for (int i=0;i<16;i++)
for (int j=1;j<=n;j++) f[i][j]=10000000000000;
f[0][n]=0;
for (int i=1;i<16;i++)
for (int j=1;j<=n;j++)
for (int k=1;k*k<=j;k++)
if (j%k==0){
if (f[i][j/k]>f[i-1][j]+log10(prime[i])*(k-1)){
f[i][j/k]=f[i-1][j]+log10(prime[i])*(k-1);
fa[i][j/k]=k;
}
if (k*k!=j&&f[i][k]>f[i-1][j]+log10(prime[i])*(j/k-1)){
f[i][k]=f[i-1][j]+log10(prime[i])*(j/k-1);
fa[i][k]=j/k;
}
}
int i=15,j=1;
ans.a[0]=ans.a[1]=1;
while (i){
if (fa[i][j]>1){
pow(prime[i],fa[i][j]-1,b);
ans=ans*b;
}
j*=fa[i][j];
i--;
}
ans.print();
}