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

  

posted @ 2014-11-25 21:15  JoeFan  阅读(210)  评论(0编辑  收藏  举报