bzoj1225 [HNOI2001] 求正整数
1225: [HNOI2001] 求正整数
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 762 Solved: 313
[Submit][Status][Discuss]
Description
对于任意输入的正整数n,请编程求出具有n个不同因子的最小正整数m。例如:n=4,则m=6,因为6有4个不同整数因子1,2,3,6;而且是最小的有4个因子的整数。
Input
n(1≤n≤50000)
Output
m
Sample Input
4
Sample Output
6
分析:这道题和反素数这道题非常像.
涉及到因数个数,可以很容易想到公式(k1 + 1) * (k2 + 1) *......*(kn + 1),那么先把可能的质数给求出来,枚举次数.这道题我们是预先知道了因数的个数,那么枚举的次数就要满足条件:+1后整除因数个数。dfs一下答案就出来了
但是这样要用到高精度,每一次都高精度很麻烦啊,能不能在中间过程时不用高精度呢?可以的,只要我们在运算的时候取对数就好了.目的就是方便比大小,不用高精度,最后输出的时候用高精度就可以了.
只涉及到高精度数比大小并且满足对数运算律似乎都可以用对数运算来避免中途高精度运算.我感觉目前只能用到log(xy) = logx + logy和logx^k = k*logx,在搜索的时候分步运算合并即可.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> #include <cfloat> using namespace std; int n,prime[] = {0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53},tot = 16; double minn = DBL_MAX,llg[21]; int res[21],ans[20],p[2000001],len; void print() { len = p[1] = 1; for (int i = 1; i <= 16; i++) { for (;ans[i] > 0;ans[i]--) { for (int j = 1; j <= len; j++) p[j] *= prime[i]; for (int j = 1; j <= len; j++) { p[j + 1] += p[j] / 10; p[j] %= 10; } if (p[len + 1]) len++; while (p[len] / 10 != 0) { p[len + 1] += p[len] / 10; p[len] %= 10; len++; } } } for (int i = len; i >= 1; i--) printf("%d",p[i]); printf("\n"); } void dfs(double sum,int cnt,int x) { if (sum >= minn) return; if (cnt == 1) { minn = sum; memset(ans,0,sizeof(ans)); for (int i = 1; i <= x - 1; i++) ans[i] = res[i]; return; } if (x > 16) return; for (int i = 0; (i + 1) * (i + 1) <= cnt; i++) if (cnt % (i + 1) == 0) { res[x] = i; dfs(sum + i * llg[x],cnt / (i + 1),x + 1); if ((i +1) * (i + 1) != cnt) { res[x] = cnt / (i + 1) - 1; dfs(sum + (cnt / (i + 1) - 1) * llg[x],i + 1,x + 1); } } } int main() { scanf("%d",&n); for (int i = 1; i <= 16; i++) llg[i] = log(prime[i]); dfs(0,n,1); print(); return 0; }