数论从这里开始——一个数的因数

数论从这里开始——一个数的因数

数论又多又难,该从哪开始学呢?不如先思考一下下面这个问题:

对于一个自然数n,它的因数是什么?

一、因数的筛法

1.最简单的暴力

相信只要你有一点数学和编程基础的话,都会想到下面这个最简单暴力的方法:

1 int find_factor(int x)

2 {

3 int i,cnt=0;

4 for(i=1;i<=x;i++)

5 if(x%i==0) cnt++;

6 return cnt;

7 }

对,只要从1到n遍历一遍,看看是不是n的因数就解决了。但是这样的话有一个缺点,该算法的时间复杂度为O(n),数据稍微一大,就超时了。

2.修改后的筛法

那么我们能不能稍微改进一下这个算法呢?答案是可以的,我们都知道一个数的因数一定是成对出现的,那么对于每一组里小的那个因数,它的大小不会超过,利用这一点我们可以将我们的算法做如下改进:

1 int find_factor(int x)

2 {

3 int i,cnt=0;

4 for(i=1;i*i<=x;i++)

5 if(x%i==0)

6 {

7 if(i*i==x) cnt++; //当x=i*i时,计数器只需加一次

8 else cnt+=2;

9 }

10 return cnt;

11 }

这样一来,我们的时间复杂度就变为了O(),可以解决更大范围的数据了。上面的筛法也是在大多数题目中适用的。

3.加强版筛法

但是还是有更加善良的出题人,想要继续考察我们,这就需要我们学习专业的数学知识了。我们先来看下面两个概念:

·分解质因数:把n表示为质数相乘的形式,如30=2×3×5。我们可以用下面的代码实现分解质因数(时间复杂度O()):

1 #include

2

3 using namespace std;

4

5 void resolved()

6 {

7 int i,n,temp;

8 scanf("%d",&n);

9 printf("%d=",n);

10 temp=n;

11 if(n<2) return ; //小于2的数不合法,若n为质数则输出它本身

12 for(i=2;i*i<=temp;i++) //根号n复杂度

13 while(temp%i==0)

14 {

15 temp=temp/i;

16 printf("%d",i);

17 if(temp!=1) printf("*");

18 }

19 if(temp!=1) printf("%d",temp); //当n为质数

20 return ;

21 }

22

23 int main()

24 {

25 resolved();

26 return 0;

27 }

分解质因数

(还有一个时间复杂度为O()的算法,日后再补)

既然这些因数都是质数,我们可以把一个数n的分解质因数表示为:

其中,p1、p2、p3…pk是由小到大的质数,如:36=2×2×3×3=22×32。

·约数个数定理:对于一个大于1正整数n可以分解质因数:

则n的正约数的个数就是:

其中a1、a2、a3…ak是p1、p2、p3…pk的指数。

感觉不太好理解?我们来看下面几个实例:

(1)10=2×5=21×51

10的因子:1(20×50),2(21×50),5(20×51),10(21×51),

因子的个数=4=(1+1)×(1+1);

(2)36=2×2×3×3=22×32

36的因子:1(20×30),2(21×30),4(22×30),3(20×31),6(21×31),12(22×31),9(20×32),18(21×32),36(22×32),

因子的个数=9=(2+1)×(2+1);

看完这几个例子,不知你感觉如何,接着我们用代码来实现这个过程:

1 int find_factor(int x)

2 {

3 int cnt=1,p=2; //p代表素数

4 while(x!=1)

5 {

6 int t=1; //t最终代表(a[i]+1)

7 while(x%p==0)

8 {

9 x=x/p;

10 t++;

11 }

12 p++;

13 cnt*=t;

14 }

15 return cnt;

16 }

这个方法不光可用用来求一个数的因数的个数,还可以用来解与因数个数相关的问题。

二、约数个数定理的应用

我们来看下面几个问题:

1.求1到n里面约数最多的数的约数个数(n<=1018) 这个题注意数据!!!一看到这个数据我们就知道暴力是不可能实现的,那么又如何使用上面的方法呢?如果用上面的方法进行枚举也是不可取的。那么我们来简单分析下这个问题:·我们知道每一个数都可以用质因子的积表示,而约数的个数只与指数有关!

·我们知道pn>...>p3>p2>p1,那么假设我们存在某一个ak>a1 那么我们交换pk与p1的指数,显然约数个数不变,但是数变小了!

如:24=23×31和54=21×33。

·也就是说对于任何n,m如果pn>pm那么an

1 #include

2

3 using namespace std;

4

5 int prime[25]={1,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89}; //存一下质数

6 long long n,ans;

7

8 //pos代表第几个质数,num代表目前因子的个数,multi代表目前的数,len代表循环的次数

9 void get_num_dfs(int pos,long long num,long long multi,int len)

10 {

11 int i;

12 if(multi>n) return ;

13 if(multi<=n) ans=max(ans,num);

14 for(i=1;i<=len;i++)

15 {

16 long long temp=pow(prime[pos],i);

17 if(multi>n/temp) break; //用除法防止爆long long

18 get_num_dfs(pos+1,num*(i+1),multi*temp,i); //进行下一个状态

19 }

20 return ;

21 }

22

23 int main()

24 {

25 int t;

26 scanf("%d",&t);

27 while(t--)

28 {

29 ans=0;

30 scanf("%lld",&n);

31 get_num_dfs(1,1,1,64);

32 printf("%lld\n",ans);

33 }

34 return 0;

35 }

Author : Houge Date : 2019.5.27

Update log :

2019.5.30:修正了一处错误。

相关推荐

dnf不能双开了?原因是什么?怎么办?
第365用英语怎么说

dnf不能双开了?原因是什么?怎么办?

📅 07-30 👁️ 8710
国风·鄘风·蝃蝀
第365用英语怎么说

国风·鄘风·蝃蝀

📅 07-10 👁️ 6133
釣的解释
365bet365官网

釣的解释

📅 07-25 👁️ 6495