原题链接:198. 反素数 - AcWing题库
解题思路:因为每个合数都能由质数组成,所以在知道一个数的质因数分解后,便可以通过公式求出每一个数的约数。额外加1是因为这个数可以不选择该质数,等价于乘以该质数的0次方。
(Ci对应的是每个质数的指数)
而从题目中可以得知最大范围。由最大范围可得以下两个限制条件:只需要考虑最小的10个质数,所有质数的指数之和不超过30。第一个限制条件是因为10个质数相乘便以及超过了2e9,而第二个限制条件也是类似的原因,2^30已经超过,不需要考虑更高范围的数字了。
接着只需要找出约数最多的数字中最小的那一个,因为比其大的数字都不符合条件。为了保证能找到最小的数字,应当保证Ci-1>Ci。因为指数的集合相同时,更大的指数对应更小的质数能让值更小。通过以上限制条件范围已经极小,可以通过DFS完成答案的查找。
AC代码:
#include<bits/stdc++.h>
using namespace std;
int prime[11]={0,2,3,5,7,11,13,17,19,23,29},c[11]={0};//prime记录前10个质数,c记录对应位置质数的指数
long long max_num=1,max_div=1,n;//max_num记录合法的数据初始值,顺带做1特判,max_div记录当前最大的合法数的约数数量
void dfs(long long buf_num,long long buf_div,int now){//buf_num记录当前值,buf_div记录当前值的约数,now记录层数,即到了第几个质数
if(now==11){//到达11层时说明前10个质数都已经选过,开始判断是否需要更新
if(buf_div>max_div||(buf_div==max_div&&buf_num<max_num)){//如果约数大于最大值则直接更新,如果相等则选较小的数
max_div=buf_div;
max_num=buf_num;
}
return;
}
for(int i=0;buf_num<=n&&i<=c[now-1];i++){//循环该质数数量,直到大于n或者该质数的指数超过前一个质数的指数为止
c[now]=i;
dfs(buf_num,buf_div*(c[now]+1),now+1);
buf_num*=prime[now];
}
}
int main(){
cin>>n;
c[0]=0x7fffffff;//因为c[1]是2,而2是实际上的第一个质数,可以不受前一个质数的指数限制,所以初始化一下赋最大值(超过30就行了)
dfs(1,1,1);
cout<<max_num;
return 0;
}