BIT1048 n以内约数最多的数

题意:

做题时参考了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;
}



你可能感兴趣的:(BIT1048 n以内约数最多的数)