Number With The Given Amount Of Divisors

*G - Number With The Given Amount Of Divisors

Given the number n, find the smallest positive integer which has
exactly n divisors. It is guaranteed that for the given n the answer
will not exceed 1018.


Input
The first line of the input contains integer n (1 ≤ n ≤ 1000).


Output
Output the smallest positive integer with exactly n divisors.


Examples
Input
4
Output
6
Input
6
Output
12**

 思路:

这是一道典型的反素数的题目,我也是想了很久才能把代码看懂,代码不长,但是非常难懂。如果理解了其中的思想还是很有意思的(但是我做的时候一点也没感到有意思),哈哈,话不多说,先来看看这道题目。

大意

对于一个正整数n,找到一个数X,X的因子数为n,且X最下也就是,X=min({因子数为n的集合}),而满足这样的X称为反素数。

解题:

X=2^m1*3^m2*5^m3***********p^mn;X的因子总数为(m1+1)*(m2+1)*******(mn+1);大家把这个看明白了就很好解了。按照这个思路,写出递归深搜算法。如果还不理解的话,大家可以参考下资料,搜索反素数会有大量的资料。耐下心来,不要浮躁,一定会弄懂的。

 参考资料:

1、stupid_one 博客

随手记录,持之以恒。(•̀ᴗ•́)و反素数就是区间内约数个数最多的那个数。

在ACM题目里,

一般是求约数最多而且数字最小的那个数,【1--n】

二是求约数刚好等于n的最小的那个数

三是求区间里的最小反素数【beign,end】

1和3有区别吗?有,1可以加速,3只能暴力

先说下思路

思路 : 官方题解 : 

(1)此题最容易想到的是穷举,但是肯定超时。

(2)我们可以知道,计算约数的个数和质因数分解有着很大的联系: 若Q的质因数分解为:Q=p1^k1*p2^k2*…*pm^km(p1…pm为素数,k1…km≥1),则Q有(k1+1)(k2+1)…(km+1)个约数。但是质因数分解的时间复杂度很高,所以也会超时。

(3)通过以上的公式,我们可以“突发奇想”:为何不能把质因数分解的过程反过来呢? 这个算法就是枚举每一个素数。初始时让m=1,然后从最小的素数2开始枚举,枚举因子中包含0个2、1个2、2个2…k个2,直至m*2^k大于区间的上限N。在这个基础上枚举3、5、7……的情况,算出现在已经得到的m的约数个数,同时与原有的记录进行比较和替换。直至所有的情况都被判定过了。 这个算法的优化:如果p1*p2*p3*……*pk>N(pi表示第i个素数),那么只要枚举到p k-1,既不浪费时间,也不会遗漏。

(4)以上的算法还不是最好的,还可以继续优化。 我们看以下的例子: 6=2*3 10=2*5 6和10的质因数分解“模式”完全相同,所以它们的约数个数是相同的。但是由于3<5,所以6<10。 12=2^2*3 18=3^2*2 12和18的质因数分解“模式”完全相同,所以它们的约数个数是相同的。但是由于12的质因数分解中2的指数大于3的指数,18的质因数分解中3的指数大于2的指数,所以12<18。 根据以上的举例,我们也可以对(3)中的算法进行一个改进:可以在枚举时进行一个优化,使得枚举到的数字中2的指数不小于3的指数,3的指数不小于5的指数……这样我们就能够得到质因数分解“模式”相同的最小数(证明略)。再对于每一个得到的数进行比较和记录。这个算法的优化力度极大,效率几乎达到了极限。

下面是代码部分

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ull unsigned long long
 
const ull inf = ~0ULL;
 
int p[16] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};//这16个素数乘起来接近于ull最大值 
//因为质因数的指数不递减,所以所以指数为1的时候不爆ull的最多16个质数
int n;
ull ans;
 
void dfs(int dep, ull tmp, int num){
  //深度,当前数的值,因数的个数
  	if(num > n)//因数多于n回溯
  	{
  		return ;
	  }
  	if(num == n && ans > tmp) ans = tmp;
  	
  	for(int i = 1; i <= 63; i++){ //枚举指数
    if(tmp  > ans / p[dep])break; //满足最小
    dfs(dep + 1, tmp *= p[dep], num * (i + 1));
  } 
}
 
int  main(){
  while(cin>>n){
    ans = inf;
    dfs(0, 1, 1);
    cout << ans << endl;
  }
  return 0;
}

注:个别文字摘抄与网络,如有侵权,请私信联系删除,本文不用做盈利。

猜你喜欢

转载自blog.csdn.net/weixin_43442778/article/details/84667935