http://acm.timus.ru/problem.aspx?space=1&num=1748
题意:给定一个数n,要求一个不超过n的数,并且因子数最多的最小的数。
也就是反素数
根据反素数的性质,每个反素数必然是由一系列【连续】质因子组成,并且较小的因子的次数一定比较大的因子的次数大 (不满足这两个条件必然可以找到一个 更小的数 且因子数与该数相同 ,矛盾)
所以我们dfs搜即可。
搜索控制两个条件
1:第k个因子的最高次比k-1的最高次低
2:因子数的话,可以根据 定理1: 一个正整数 n 可以用***素***因子唯一表示为 p1^r1 * p2^r2 * ... pk^rk (其中 pi 为素数) , 那么这个数的因子的个数就是,(r1+1)*(r2+1)~(rk+1).来求
搜索过程的话,如果发现当前乘积已经大于n了,就可以break掉
本题数据比较大。 这个判断用乘法会溢出,所以改用除法就好了
0.28s
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <queue> #include <map> #include <set> #include <vector> #include <iostream> using namespace std; #define ll __int64 #define ull unsigned __int64 const double pi=acos(-1.0); double eps=0.000001; int prime[]={1,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53}; ll ans; ll num; ll n; void dfs(int k, ll now,ll cnt,int last)//求1-n最大反素数,初始化ans=n,num=1 //k是层数,now是当前的乘积,cnt是当前的数对应的因子数,last是最后一个因子的最高次数 { if (now>n) return; //剪枝,比判k==17快 //if (k==17) return ; if ( cnt>num) //更新答案 { ans=now;num=cnt;} else if(cnt==num) { if (now<ans) ans=now; } ll t=prime[k],i; //t是素因子的方幂 for (i=1;i<=last;i++) //last是最高次,显然当前素因子最高次不超过前面的最高 { if (t>n/now) break; //乘法溢出 dfs(k+1,now*t,cnt*(i+1),i); t*=prime[k]; } } int main() { int t; cin>>t; while(t--) { num=1; scanf("%I64d",&n); ans=n; dfs(1,1,1,60); printf("%I64d %I64d\n",ans,num); } return 0; }