|
发表于 2022-2-7 10:33:02
|
显示全部楼层
本帖最后由 guosl 于 2022-2-7 11:29 编辑
本题的数学理论的结论请参考108题中我的论述,这里就不再啰嗦了。
做本题还需要知道的一件事是:一个数x的素因数分解为p1^k1 ... pn^kn,则这个数的因子个数为:(k1+1)*...*(kn+1)。
由于本题中涉及的数值太大,我们使用了mpir大数值库(具体参考:http://www.mpir.org/)。
对于值M=2*3*...*47(即前15个素数的乘积)就是一个满足条件的数。但可能不是最小的值,但是根据这个值我们可以得出以下的结论(数学的证明略):
1. 这个最小值小于等于M。
2. 如果令N为欲求的最小值那么在这个N的素因数分解中一定不会出现值比47还大的素数。
3. N的素因数分解中一定是从2开始的连续若干个素数。
为此,我们只需用深度搜索即可。
- /*
- 答案:9350130049860600
- 耗时:0.108634秒
- */
- #include <iostream>
- #include <algorithm>
- #include <mpirxx.h>
- #include <omp.h>
- using namespace std;
- const int N = 8000000;//为n^2的因子数,同时也是n^2的分解数的2倍,为因子数搜索达到要求的值
- const int p[15] = { 2,3,5,7,11,13,17,19,23,29,31,37,41,43,47 };
- mpz_class M = 1; //搜索的上界也是最后的结果
- void dfs(int k, //搜索的深度
- int fs, //当前值z^2的因子数
- mpz_class z) //当前的值
- {
- if (k >= 15)//迭代深度到底了
- return;
- if (z > M)//迭代的计算值超过了当前的值,没有再做下去的意义了
- return;
- if (fs > N)//因子数达到了要求
- {
- M = min(M, z);//保留最小值
- return;
- }
- mpz_class z1 = z*p[k];//当前的计算值
- int x = 1, fs1 = fs*(2 * x + 1);//当前z1^2的因子个数
- while (z1 < M)//进行搜索
- {
- dfs(k + 1, fs1, z1);
- ++x;
- z1 *= p[k];
- fs1 = fs*(2 * x + 1);
- }
- }
- int main(void)
- {
- double t = omp_get_wtime();
- for (int i = 0; i < 15; ++i) //先求出一个初步的估值
- M *= p[i];
- dfs(0, 1, 1);//深搜结果
- t = omp_get_wtime() - t;
- cout << M << endl << t << endl;//输出结果
- return 0;
- }
复制代码 |
|