由于上一次做的线段树用到反素数,觉得很神奇,所以在这学习了一下。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4133
关于反素数的定义参见百度百科:http://baike.baidu.com/view/2621997.htm
关键还是代码,参照反素数性质剪枝搜索。关于我的理解都写在代码注释里了。代码就是百度百科的
#include <stdio.h>
#include <string.h>
/*性质一:一个反素数的质因子必然是从2开始连续的质数.*/
const __int64 prime[16] = {1,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47};
__int64 maxsum, bestnum, n;//maxsum最优解时的因数个数, bestnum是最优解
/*
num:当前枚举到的数,k:枚举到的第k大的质因子;sum:该数的约数个数;limit:质因子个数上限;
*/
void dfs(__int64 num, __int64 k, __int64 sum, __int64 limit)
{
if (sum > maxsum) //如果约数个数更多,将最优解更新为当前数;
{
maxsum = sum;
bestnum = num;
}
else if (sum == maxsum && bestnum > num)
{
bestnum = num; //如果约数个数相同,将最优解更新为较小的数;
}
if (k>15)//枚举的数超过 prime数组元素个数。
{
return;
}
__int64 temp = num, i;
for (i=1; i<=limit; i++)//利用性质2:p=2^t1*3^t2*5^t3*7^t4.....必然t1>=t2>=t3>=....
{
if (temp * prime[k] > n)
{
break;
}
/*
temp为乘上一个第k个质因数的值
k+1是指向下一个质因数
sum*(i+1): 假设 p=2^t1*3^t2*5^t3*7^t4,则他的约数个数是(t1+1)*(t2+1)*(t3+1)*(t4+1)
加一的原因自己想想应该很简单
所以sum*(i+1)就是temp的约数个数
i就是下一个质因数的上限,就是性质2;
*/
temp = temp * prime[k];
dfs(temp, k+1, sum * (i+1), i);
}
}
int main()
{
int T, Cas = 1;
scanf("%d", &T);
while (T--)
{
maxsum = 0;
bestnum = 0;
scanf("%I64d", &n);
dfs(1, 1, 1, 50); //k要从1开始,因为prime[0] = 1;1不是质因数
printf("Case #%d: %I64d\n", Cas++, bestnum);
}
}