题目大意:一个正整数,如果它的约数个数比所有比它小的正整数的约数个数都大,则称这个数为反质数,求不超过N(1≤N≤2000000000)的最大反质数。
做法:当初一拿到这题瞬间蒙了,不知道这是什么鬼,后来了解约数定理之后发现这就是个裸的DFS啊!约数定理是指,一个数的约数个数等于它分解质因子后的每个质因子的指数+1的乘积,用一个具体的例子来说,例如1800这个数,分解质因子后得到的式子为2^3*3^2*5^2,2的指数是3,3的指数是2,5的指数是2,因此1800的约数个数为:(3+1)*(2+1)*(2+1)=36个。这个定理可以很容易的用组合数学的方法来证明。然后就可以愉快的DFS了,思路非常简单,从小到大枚举质因子和它的指数,记录下满足条件的最大数字和它的约数个数即可。需要注意的是解的替换,如果当前数字的约数个数比前面求出的解的约数个数大,则必须替换,因为在这种情况下,说明当前数字比已知解更优或已知解不满足条件。如果当前数字的约数个数与前面求出的解的约数个数相等而数字比已知解小,则说明已知解不满足条件,也要替换。可以证明搜索的深度不超过30。
以下是本人代码:
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
long prime[21]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47};
long long n,maxi=0,maxn=999999999; //maxn,maxi:满足条件的最大数和它的约数个数
void search(long long x,long long s,long long p) //x,s,p:当前数字,当前数字的约数个数和枚举到的质因子序号
{
if (s>maxi) {maxi=s;maxn=x;}
if (s==maxi&&x<maxn) maxn=x;
if (s<maxi&&x>maxn) return;
int total=0;
while(x*prime[p]<n)
{
total++;
x*=prime[p];
search(x,s*(total+1),p+1);
}
}
int main()
{
cin >> n;
search(1,1,1);
cout << maxn;
return 0;
}