关于反素数的概念参考题目链接
- 素数是因子最少的数,那么反素数就是因子多的数,如果在一个数之前所有的数因子数量小于这个数的因子数量,那么这个数就是一个反素数
- 那么怎么解这个问题呢?
要求解这个问题,首先要知道几个结论, - 首先是唯一分解定理:任何数都可以拆成n个素数乘积的形式,且唯一
- 如果一个数可以写成233251这种形式,那么它有多少个因子呢?根据排列组合的知识,可以明白是4*3*2=24个,也就是选择多少个2,多少个3,多少个5的问题
- 将一个数的最小质因子按照从小到大的顺序排列起来,如果这个数是反素数。那么它们的指数应该是从大到小的。因为如果不是这样,那么它之前一定有某个数的因子数比它多,这样他就不是反素数了
总结一下就是:x的因数应该最多,且如果存在因数相等的情况,那么x应该是最小的那一个(如果取大的那一个,那么就存在一个更小的数因数和它相等,这样不符合反素数严格大于的性质) - 如果理解了这样几个结论,那么对于这个问题,题目的n最大是2e9,这个数介于2的30次方和31次方之间,所以质因子指数和最大也就是30,可以使用搜索的方法进行爆搜,找到小于n的最大反素数,这需要记录当前找到的数的因子个数,从而不断更新答案
#include <iostream>
using namespace std;
int n;
typedef long long ll;
const int MAXN = 2e5 + 100;
int p[MAXN];
int vis[MAXN];
ll ans;
int num;//ans表示答案,num表示当前答案的因子数
int prime;//质数个数
int Prime(){
int tot = 0;
for(int i=2;i<=50;i++){
if(!vis[i]) p[tot++] = i;
for(int j=0;j<tot&&i*p[j]<=50;j++){
vis[i*p[j]] = 1;
if(i % p[j] == 0) break;
}
}
return tot;
}
void dfs(ll now, int number, int m){//now表示当前数是多少,number表示当前因数数量,m表示到第几个质数了
if(m >= prime) return;
//因数数量小于当前显然需要更新为当前
//如果因数个数和当前相等,那么答案应该更新为小的那一个(反素数因子个数严格大于前面的数的性质)
if(number > num || number == num && ans > now){
ans = now;
num = number;
}
for(int i=1;i<=31;i++){
if(p[m] * now > n) break;
now *= p[m];
dfs(now, number * (i + 1), m + 1);//这里的number进行的改动就是在前面我说的排列组合
//如果i为1,那么说明p[m]的指数为1,那么就有i+1=2种情况
}
}
int main(){
prime = Prime();
cin>>n;
dfs(1, 1, 0);
cout<<ans;
return 0;
}