解题思路:这题一看数据就不可能暴力的,但是我们可以先打个表试一下,发现题目所求的反质数分布非常的稀疏。所以解法一就是打表,打表有3种方法:
解法一:
一:直接暴力枚举因子(这种应该没什么人去做吧,太慢了)
二:枚举到sqrt(i),但是对于这么大的数据显然还是太慢了。
三:一个性质,约数个数定理:一个正整数n,可以分解成 (p1,p2...pn为素数)那这个数的约数个数为
(k1+1)*(k2+1)...(kn+1),这个不难理解,考虑p1^k1它的约数有p1^0~p1^k1共(k1+1)个,一直到pn^kn有(kn+1)个约数,根据乘法原理那n的约数个数就是(k1+1)*(k2+1)...(kn+1),因为每个单独的部分元素(如p1^2)都是n的约数,而且由于是素数的次方相乘起来唯一不重复,那搭配起来也是n的约数。
考虑到题意反质数就是约数相同的情况下数最小的那一个,那就是(k1+1)*(k2+1)...(kn+1)定,那我想要这个数小,那肯定是把大的k给小的p。所以我们可以得出k1,k2.....kn一定是不递增的。当k1,k2.....kn都取1时,前十个素数相乘已经大于2e9了,所以考虑前十个素数就行了。
先看打表的代码,只要表打出来了,那就非常简单明了了。
//打表
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int maxn=2e9+5;
int prime[10]={2,3,5,7,11,13,17,19,23,29};
int main(){
std::ios::sync_with_stdio(0);
int count=0;
for(int i=2;i<=maxn-5;++i){
int tp=i,num=1;
for(int j=0;j<10;++j){
int cnt=0;
while(tp%prime[j]==0){
tp/=prime[j];
cnt++;
}
num=num*(cnt+1);
if(tp==1) break;
}
if(num>count){
cout<<i<<",";
count=num;
}
}
return 0;
}
#include<bits/stdc++.h>
using namespace std;
int n;
int a[68] = {1, 2, 4, 6, 12, 24, 36, 48, 60, 120, 180,
240, 360, 720, 840, 1260, 1680, 2520, 5040, 7560, 10080,
15120, 20160, 25200, 27720, 45360, 50400, 55440, 83160, 110880,
166320, 221760, 277200, 332640, 498960, 554400, 665280, 720720,
1081080, 1441440, 2162160, 2882880, 3603600, 4324320, 6486480,
7207200, 8648640, 10810800, 14414400, 17297280, 21621600, 32432400,
36756720, 43243200, 61261200, 73513440, 110270160, 122522400,
147026880, 183783600, 245044800, 294053760, 367567200, 551350800,
698377680, 735134400, 1102701600, 1396755360};
int main(){
std::ios::sync_with_stdio(0);
cin>>n;
for(int i=67;i>=0;--i){
if(a[i]<=n){
cout<<a[i]<<endl;
break;
}
}
return 0;
}
解法二:
搜索也是用的约数定理,然后利用k1,k2.....kn一定是不递增的这一条件,枚举各个质数的指数,还是很好懂的,代码如下:
#include<bits/stdc++.h>
using namespace std;
const int inf=0x7f7f7f7f;
typedef long long ll;
ll prime[15]={0,2,3,5,7,11,13,17,19,23,29};
ll num[15];
ll ans,n,apnum;
//ans表示答案,apnum表示答案的约数个数
void dfs(ll step,ll pnum,ll state){//第几个质数,现在的约数个数,现在的值
if(step>=12) return;
if(pnum>apnum || (pnum==apnum&&state<ans)){
ans=state,apnum=pnum;
}
num[step]=0; //每一轮都要从0开始
while(state*prime[step]<=n && num[step]+1<=num[step-1]){
num[step]++;
state*=prime[step];
dfs(step+1,pnum*(num[step]+1),state);
}
}
int main(){
std::ios::sync_with_stdio(0);
cin>>n;
num[0]=inf;
dfs(1,1,1);
cout<<ans<<endl;
return 0;
}