牛客网练习赛14 — n的约数

题目:

题目描述 

t次询问,每次给你一个数n,求在[1,n]内约数个数最多的数的约数个数


1 <= n <= 1000000000000000000(18个0)


参考了大佬的代码,自己理解的,还有一部分还没有搞明白

首先,每一个正整数都能通过互不相同的素数的次方的积得出,下面是一条公式

设n=p1^k1*p2^k2*……*pn^kn,其中p1,p2,……,pn为互不相同的质数,k1,k2,……,kn为正整数;

所谓的约数就是能被n整除的正整数,我们把其中p1^k1移出来,显然p1^k1能被n整除,同理的p1^0,p1^1,p1^2一直到p1^k1都能被n整除,那么单单就p1^k1来说,能被n整除的数就有(k1+1),这个+1是包含p1^0的情况,以此类推,n的全部约数就有   (k1+1)*(k2+2)*……*(kn+1)个,这个结论很重要;

接下来只要枚举小于或者等于n的所有 p1^k1*p2^k2*……*pn^kn的组合,然后进行比较 (k1+1)*(k2+2)*……*(kn+1)的大小,选取最大的那个,就是答案;

下面是参考的是大佬的代码:代码下面对代码稍作一下解析(自己的理解)

#include
#include
#include
#include
#include
#define ll long long
using namespace std;
int p[20] = { 0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47 }, T;
ll n;
int dfs(ll num, int pos, int k, int ans) { //num为当前的数值,pos为当前素数的位置,k为当前素数的个数,ans为当前因子的个数
	if (pos>15) return 0;
	int ret = ans;
	for (int i = 1; i <= k; ++i) {
		if (n / p[pos]

自己的理解:代码首先先列出了18个素数,在参考了其他大佬的代码,发现很多都是列大于或等于16个的素数就行了,这里我不太明白,感觉不是很够用,这些列举的素数是用来枚举上面所说的组合的,这里用到了dfs来进行计算和比较大小,具体过程是这样的:

    给定一个限制的素数最大次方数  64 (有些大佬的ac代码用了111)

    起始的数字num=1,使用的素数为事先列举的素数数组p中pos=1的素数,然后是一个限制的素数最大次方 k = 64 ,起始约数ans=1; 

  这里有一点要注意的是,dfs的最终结束条件是  for循环里面的 n/p[pos]

代码的dfs依次是

第一种组合是 p[1]*p[2]*...*p[15], 所有素数的次方都为1。

第二种是 p[1]^2*p[2]^2*...  次方数最高的是最小的那个素数,后面的素数的次方可能为2也可能为1. 每进入一层dfs就用ret把当前约数个数记录下来,然后继续把ans*(i+1)(就是最开始讲的(k1+1)*(k2+1)*...) 带入到下一层dfs中,同时把累乘的数字num和次方限制数  i  带入下一层,进行到最后一层结束dfs的时候不断的返回上一层,然后用max来判断当前这一层ret与下一层的 约数个数的最大值,返回这个最大值然后继续返回上上层;最终能得出所有小于或者等于n的 p1^k1*p2^k2*……*pn^kn的组合的约数最大值是多少;

在这里,我还有几点没有弄明白,希望有知道的大佬讲解一下(十分感谢)

1,代码中列举的素数为19个素数,而且最大的素数是47,在n 为19位数的情况下,真的够用吗?

2,为什么dfs中  pos>15  就返回0,不太明白这个条件中15的意思,有一些大佬的ac代码用的是16;

3,在起始的限制次方数k的值为什么是64,有些ac代码用的是111;

你可能感兴趣的:(其他)