您的位置:首页 > 其它

BIT1048 n以内约数最多的数

2013-02-03 14:36 232 查看
题意:

做题时参考了http://hi.baidu.com/shuxk/item/c2b981436bfe7adac0a59213

求[1,n]中约数最多的数n<10^9

对于一个大于1正整数n可以分解质因数:n=p1^a1*p2^a2*p3^a3*…*pk^ak,

则n的正约数的个数就是(a1+1)(a2+1)(a3+1)…(ak+1) .

那么对于这题,可以用质数连乘解决

取15个质数

2,3,5,7,11,13,17,19,23,29,31,37,41,43,47

用它们任意连乘



2^a0*3^a1*......47^a14

这样的组合的约数的个数为

(a0+1)*(a1+1)*(a2+1).....(a14+1)

不断枚举这样的组合,当他大于n的时候停止

这样枚举的次数最多为10^9以内的合数的个数,至于质数,一定有2比它更优,无需考虑

这样虽然减少了很多情况,但是还是会超时

发现对于

12=2^2*3

18=3^2*2

由于约数个数相同,但是12<18,在枚举的时候加限制条件,取当前素数的个数一定小于前一个素数的个数

这样18就不会被枚举到,就减少了很多情况

具体在代码中讲

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
long long ans;
long long ansnum;//约数个数
long long n;
long long prime[15]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47};
//取20个质数
//2^a1 * 3^a2 * 5^a3 * 7^a4
void dfs(long long m,long long pi,long long m_num,long long pre)//m为当前的数,pi为当前枚举的素数,m_num为m的约数的个数,pre为之前的素数的个数
{
if(m_num>ansnum)//更新最终结果
{
ans=m;
ansnum=m_num;
}
if(m_num==ansnum&&ans>m)//更新最终结果
{
ans=m;
}
for(long long l=1;l<=pre;)//m*(prime[pi]^l),这里m不断乘以当前枚举的素数,
{
m*=prime[pi];
if(m>n)
{
break;
}
l++;//计算当前素数被乘了多少次
dfs(m,pi+1,m_num*l,l-1);//此时m的素数的个数为m_num*l
}
}
int main()
{
long long total;
cin>>total;
while(total--)
{
ans=1;//最后结果的数
ansnum=1;//最后的结果的约数的个数
scanf("%lld",&n);//n的输入
//质数连乘开始
dfs(1,0,1,LONG_MAX);//初始时从1开始连乘,从第一个素数2开始,
printf("%lld %lld\n",ans,ansnum);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: