[Jzoj] 3020. 最多的约数

题目大意

给定一个正整数 N N ,对于所有不超过 N N 的正整数,找到包含约数最多的一个数。如果有多个这样的数,那么回答最小的那个

题目解析

先给出一个定义:

W W 的质因数分解为:
W = p 1 W=p_1 a1 p 2 *p_2 a2 p m *…*p_m am ( p 1 p m a 1 a m 1 ) (p_1…p_m为素数,a_1…a_m≥1)
W W ( a 1 + 1 ) ( a 2 + 1 ) ( a m + 1 ) (a_1+1)(a_2+1)…(a_m+1) 个约数

所以,可以枚举因数中包含 0 0 2 2 1 1 2 2 k k 2 2 ,直至 m 2 k m∗2^k 大于区间的上限 N N

在这个基础上枚举 3 5 7 3、5、7…… 的情况,算出现在已经得到的 m m 的约数个数,
同时与原有的记录进行比较和替换。直至所有的情况都被判定过了

接着,给出如下例子:

12 = 2 2 3 12=2^2∗3
18 = 3 2 2 18=3^2*2

12 12 18 18 的质因数分解 模式 完全相同,所以它们的约数个数是相同的

但是由于 12 12 的质因数分解中 2 2 的指数大于 3 3 的指数, 18 18 的质因数分解中 3 3 的指数大于 2 2 的指数,所以 12 < 18 12<18

所以,可以在枚举时进行一个优化,使得枚举到的数字中 2 2 的指数不小于 3 3 的指数, 3 3 的指数不小于 5 5 的指数 …… 这样我们就能够得到质因数分解 模式 相同的最小数

代码

#include<bits/stdc++.h>
#define L long long
using namespace std;
L n,pi,ans,num;
int p[10005];
bool flag[1000010];
void fun()
{
	for(int i=2;i<=1000000;i++)
	 if(!flag[i])
	 {
	   p[++pi]=i;
	   for(int j=2;j<=1000000/i;j++)
	    flag[j*i]=1;
	 }
}
void dfs(L x,int lev,int t,int s)
{
	if(t>num||(t==num&&x<ans)) ans=x,num=t;
	int j=0,l=1,q;
	L i=x;
	while(j<s)
	{
	  j++,l++;
	  if(n/i<p[lev]) break;
	  q=t*l;
	  i*=p[lev];
	  if(i<=n) dfs(i,lev+1,q,j);
	}
}
int main()
{
	fun();
	cin>>n;
	dfs(1,1,1,30);
	cout<<ans;
}

猜你喜欢

转载自blog.csdn.net/weixin_43909855/article/details/88761817