首页 > 代码库 > [BZOJ 1053] [HAOI 2007] 反素数ant

[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;}

  

[BZOJ 1053] [HAOI 2007] 反素数ant