[BZOJ 1053] [HAOI 2007] 反素数ant
题目链接:BZOJ 1053
想一想就会发现,题目让求的 1 到 n 中最大的反素数,其实就是 1 到 n 中因数个数最多的数。(当有多于一个的数的因数个数都为最大值时,取最小的一个)
考虑:对于一个整数 n ,如何求 n 的因数的个数?
将 n 分解质因数,n = p1^a1 * p2^a2 * p2^a3 * ...... * px^ax 。(其中 pi 为质因数, ai 为质因数的指数)
那么 n 的因数的个数为 :Π (ai+1) (使用组合数学的知识很容易看出)
那么我们想要找到 1 到 n 的数中因数最多的一个,我们可以使用质数相乘,直接搜索。
注意最后的答案 Ans = p1^a1 * p2^a2 * ...... * px^ax ,满足当 p1 < p2 < p3 ... < px 时,a1 <= a2 <= a3 ... <= ax 。
因为对于某两个素数 p1, p2 (p1 < p2) ,若 a2 > a1,那么交换 a1, a2 之后,因数的个数并没有改变,相乘得到的数字却减小了,因此更优。
另外重要的一点是,我们只会用到前 10 个素数,因为前 10 个素数相乘就已经超过 n 的最大范围,使用更大的素数是没有意义的,不会更优。
代码如下:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int INF = 0x3fffffff; const int Prime[15] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29}; typedef long long LL; LL n, Ans, Cnt; void DFS(LL Num, LL MaxP, int Now, int NowCnt) { if (NowCnt > Cnt || (NowCnt == Cnt && Num < Ans)) { Ans = Num; Cnt = NowCnt; } if (Now > 10) return; LL NowNum = Num; for (int i = 1; i <= MaxP; i++) { NowNum *= (LL)Prime[Now]; if (NowNum > n) return; DFS(NowNum, i, Now + 1, NowCnt * (i + 1)); } } int main() { scanf("%lld", &n); Ans = 1; Cnt = 1; DFS(1, INF, 1, 1); printf("%lld\n", Ans); return 0; }