题意
输出不超过n的最小反素数
所谓反素数,是指比它小的数的约数个数,都严格比它少
即输出不超过n的约数最多的数
若约数个数相同,输出最小的那个
题解
首先,我们知道约数个数,ai为其素因子pi的幂次,
证明很简单,就是在那个约数里,这个素因子选几个,0个,1个,…,ai个,共ai+1种选择,累乘即可。
然后如果(ai+1)*(aj+1)相同,pi<pj,
如,约数个数均为(5+1)*(3+1)=24
我们自然是希望小的那个素因子出现的次数多,这样数小。
所以dfs暴搜的一个很有利的剪枝,就是第k个数出现个数i<=第(k-1)个数出现个数last
此外,1e16的限制,大概最多也就是十五六个素数相乘之积吧,比那个BZOJ数据范围大。
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>
#include <functional>
const int INF=0x3f3f3f3f;
const int maxn=1e5+10;
const int mod=1e9+7;
const int MOD=998244353;
const double eps=1e-7;
typedef long long ll;
#define vi vector<int>
#define si set<int>
#define pii pair<int,int>
#define pi acos(-1.0)
#define pb push_back
#define mp make_pair
#define lowbit(x) (x&(-x))
#define sci(x) scanf("%d",&(x))
#define scll(x) scanf("%lld",&(x))
#define sclf(x) scanf("%lf",&(x))
#define pri(x) printf("%d",(x))
#define rep(i,j,k) for(int i=j;i<=k;++i)
#define per(i,j,k) for(int i=j;i>=k;--i)
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
ll n,ans=1,num=1;//ans为最后的答案 num为因子个数
ll prime[]={1,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
void dfs(int k,ll now,ll cnt,int last)//当前到第k个数,当前ans,当前num,k的最大因子个数
{
if(k==17)
{
if(cnt>num||cnt==num&&ans>now)//个数尽可能多;个数相同,数尽可能小
{
ans=now;
num=cnt;
}
return;
}
int t=1;
for(int i=0;i<=last;++i)//[i,last]个第k个数
{
dfs(k+1,now*t,cnt*(i+1),i);
t*=prime[k];
if(now*t>n)break;
}
}
int main()
{
while(~scanf("%lld",&n))
{
dfs(1,1,1,10);
printf("%lld\n",ans);
}
return 0;
}
2020年3月31日补充
此题有一个弱化版本,牛客练习赛14A题 n的约数,
题目只求[1,n](n<=1e18)的拥有最大约数个数的数的约数个数是多少,可以直接利用函数返回值解决
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=101;
int p[N],tot,d[N];
ll n;
ll dfs(int x,int mx,ll v,ll res){
ll ans=res;
ll nv=n/p[x];
for(int i=1;i<=mx&&v<=nv;++i){
ans=max(ans,dfs(x+1,i,v*=p[x],res*(i+1)));
}
return ans;
}
int main(){
for(int i=2;i<N;++i){
if(!d[i])p[tot++]=d[i]=i;
for(int j=0,k;(k=i*p[j])<N;++j){
d[k]=p[j];
if(d[i]==p[j])break;
}
}
int t;
scanf("%d",&t);
while(t--){
scanf("%lld",&n);
printf("%d\n",dfs(0,10,1,1));
}
return 0;
}