数学知识—— 二.约数

定义:

若整数n除以整数d的余数为0,即d能整除n,则称d是n的约数,n是d的倍数,记为d|n。

算数基本定理的推论

一个大于1的正整数N,如果它的标准分解式为:

那么它的正因数个数为

它的全体正因数之和为

求N的正约数集合——试除法

若d>=sqrt(N)是N的约数,则N/d<=N也是N的约数。换言之,约数总是成对出现的(除了对于完全平方数,sqrt(N)会单独出现)。

所以,只需要扫描1~sqrt(N),尝试d能否整除N,若能整除,则N/d也是N的约数。时间复杂度O(sqrt(N))。

实现代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1000010;
int h[N];
int main(){
        int cnt=0;
        int x;
        cin>>x;
        int y=sqrt(x);
        for(int i=1;i<=y;i++){
            if(x%i==0){
                h[cnt++]=i;
                if(i!=x/i) h[cnt++]=x/i;
            }
        }
        sort(h,h+cnt);
        for(int i=0;i<cnt;i++)cout<<h[i]<<" ";
        cout<<endl;
    return 0;
}

试除法的推论:

一个整数N的约数上限是2*sqrt(N)。

求1~N每个数的正约数集合——倍数法

若用“试除法”来求,时间复杂度过高,为O(N*sqrt(N))。

怎么解决?

可以这样考虑,对于每个数d,1~N中以d为约数的数就是d的倍数d,2d,3d……,floor(N/d)*d。

实现代码:

vector<int> factor[500010];
for(int i=1;i<=n;i++){
    for(int j=1;j<=n/i;j++)
        factor[i*j].push_back(i);
}
for(int i=1;i<=n;i++){
    for(int j=0;j<factor[i].size();j++)
        printf("%d ",factor[i][j]);
     puts("");
}

时间复杂度O(N*logN);

倍数法的推论:

1~N每个数的约数个数的总和大约为N*logN。

最大公约数&最小公倍数

定义

最大公约数,指两个或多个整数共有约数中最大的一个。a,b的最大公约数记为gcd(a,b),同样的,a,b,c的最大公约数记为gcd(a,b,c),多个整数的最大公约数也有同样的记号。

两个或多个整数公有的倍数叫做它们的公倍数,其中除0以外最小的一个公倍数就叫做这几个整数的最小公倍数。整数a,b的最小公倍数记为lcm(a,b),同样的,a,b,c的最小公倍数记为lcm(a,b,c),多个整数的最小公倍数也有同样的记号。

定理

对于任意的自然数a,b,有:lcm(a,b)*gcd(a,b)=a*b

证明

设d=gcd(a,b),a0=a/d,b0=b/d。那么gcd(a0,b0)=1。(a0,b0互质)

所以lcm(a0,b0)=a0 * b0。

a0,b0同时扩大d倍,它们的最小公倍数也扩大d倍。(小学知识,相信你一定会 >_<)

于是lcm(a,b)=lcm(a0 * d,b0 * d)=lcm(a0,b0) * d=a0 * b0 * d=a * b/d。

证毕

求最大公约数

九章算术——更相减损术

原文:

可半者半之,不可半者,副置分母、子之数,以少减多,更相减损,求其等也。以等数约之。

翻译:

(如果需要对分数进行约分,那么)可以折半的话,就折半(也就是用2来约分)。如果不可以折半的话,那么就比较分母和分子的大小,用大数减去小数,互相减来减去,一直到减数与差相等为止,用这个相等的数字来约分。

即:
对于任意的自然数a,b且a>=b,有:gcd(a,b)=gcd(b,a-b)=gcd(a,a-b)

对于任意的自然数a,b,有:gcd(2a,2b)=2gcd(a,b)

证明:

设gcd(x,y)=d,则满足x=k1d,y=k2d,易得k1|k2。

情况1:x=y。显然,gcd(x,y)=x=gcd(x,0)=gcd(x,y-x)。

情况2:不妨令x<y,所以有k1<k2,所以y‘=y-x=(k2-k1)*d。所以应证k1|(k2-k1)。
用反证法。令k3=k2-k1。

假设k1,k3存在公约数m(m>1),即k2=p2m,k3=k2-k1=p3m=(p2-p1)*m。

所以:k1=p1m,k2=p2m=(p3+p1)*m且p1|(p3+p1)。

要使k1|k2,所以m=1,与假设矛盾,所以k1|(k2-k1)。
所以原命题得证。

综上,gcd(x,y)=gcd(x,y-x)。

当然,此结论可用数学归纳法推广到一般,该性质对多个整数都成立。

代码实现:

#include<iostream>
using namespace std;
int main(){ 
    int a,b; 
    cin>>a>>b; 
    while(a != b){ 
        if(a > b) 
            a -= b; 
        else 
            b -= a; 
     } 
     cout<<a<<endl; 
     return 0;
}

辗转相除法(又名:欧几里德算法)

对于任意的自然数a,b,有:gcd(a,b)=gcd(b,a mod b)

证明:

若a<b,则gcd(a,b)=gcd(b,a mod b)=gcd(b,a),命题成立。

若a>=b,则:

(来自:百度百科)

比较:
更相减损术和辗转相除法的主要区别在于前者所使用的运算是“减”,后者是“除”。从算法思想上看,两者并没有本质上的区别,但是在计算过程中,如果遇到一个数很大,另一个数比较小的情况,可能要进行很多次减法才能达到一次除法的效果,从而使得算法的时间复杂度退化为O(N),其中N是原先的两个数中较大的一个。相比之下,辗转相除法的时间复杂度稳定于O(logN)。

但是由于高精度除法取模不易实现,在高精度情况下,优先考虑更相减损术。

原文地址:https://www.cnblogs.com/zhukaiyuan/p/11600602.html

时间: 2024-10-13 21:14:50

数学知识—— 二.约数的相关文章

关于一部分数学知识》(工具向)(实时更新)

这里汇总一下关于联赛的一些数学知识,以后做到有些关于数学的题就可以较快的解决(和愉快的装13). 1.组合数 这个应该是高中数学就学过的知识,在这里详细的介绍就不给出了,可以自行百度. 公式一: 这个比较好理解,在备选的n个里面找一个一定不选,那么我们就一定要在其他n-1个备选数里找出m个数字,所以有c(n-1,m),但如果一定要选刚才没有选的那一个,就要去掉这个,从剩下的n-1个里面取m-1个,所以有c(n-1.m-1):对于每一个m这样做结果是重复且一样的,所以得出Pascal公式. 公式二

3D Game Programming withDX11 学习笔记(一) 数学知识总结

在图形学中,数学是不可或缺的一部分,所以本书最开始的部分就是数学知识的复习.在图形学中,最常用的是矢量和矩阵,所以我根据前面三个章节的数学知识,总结一下数学知识. 一.矢量 数学中的矢量,拥有方向和长度.其实矢量和点在坐标系中的表示完全一致(笛卡尔坐标系为准),区分矢量和点的关键,我觉得就是做平移.点是不能用平移操作来保证一致的,比如点A(1,2,3)经过平移矢量(1,2,3)后就是B(2,4,6),此时就是一个新的点.但是矢量经过相同平移操作后,还是矢量(1,2,3),这是因为矢量表示的是 v

canvas绘图数学知识总结

题外话: 最近看了一本书叫 <HTML5 Canvas核心技术 图形.动画与游戏开发>已经算是看了85%,基本接近尾声,所以近期会多总结一些关于canvas的东西, 这本书讲的还算可以,最大的障碍就是一些数学知识和理论的应用,第八章的碰撞检测比较难理解,看这部分的时候,我感觉非常吃力,向量运算是主要技术点, 我这本书是以阅读源码为主的,有兴趣的朋友可以看看,大家交流一下. 三角函数 canvas中所有和角有关的api 都是用的弧度 js api 如 Math.sin(),Math.cos,Ma

整理一下CoreGraphic和Quartz2D的知识(二)

利用Quartz2D绘图的基本步骤 •1. 获取与视图相关联的上下文对象 –UIGraphicsGetCurrentContext •2. 创建及设置路径 (path) –2.1 创建路径 –2.2 设置路径起点 –2.3 增加路径内容…… •3. 将路径添加到上下文 •4. 设置上下文属性 –边线颜色.填充颜色.线宽.线段连接样式.线段首尾样式.虚线样式… •5. 绘制路径 •6. 释放路径 什么是路径::? •路径定义了一条或者或多条形状或子路径 •子路径可以包含一条或者多条直线或曲线 •子

ACM数学知识体系

#include<iostream> #include<string> #include<stack> using namespace std; #define n 8 stack <int *> s; int * createMaze(){//初始化迷宫 int i,j; int * a; a=new int[n*n]; for(i=0;i<n;i++){ for(j=0;j<n;j++){ *(a+n*i+j)=-1;//不设置为0的原因是超

编程需要知道多少数学知识?

数学和编程有一种容易让人误解的联系.许多人认为在开始学习编程之前必须对数学很在行或者数学分数很高.但一个人为了编程的话,需要学习多少数学呢? ([伯乐在线编注]:本文仅为 Al Sweigart 一家之言,再推荐 Alan Skorkin 的这篇文章<数学是成就卓越开发人员的必备技能>.) 实际上不需要很多.这篇文章中我会深入探讨编程中所需要的数学知识.你可能已经都知道了. 对于基本的编程,你需要知道下面的: 加减乘除 - 实际上,电脑会帮你作加减乘除运算.你仅需要知道什么时候运用它们. 模运

【Cocos2D学习】Lua——数学知识的基本应用

学习Cocox,真的是相当麻烦,IDE的支持太差了,Cocox的各种版本也是多种多样,我先研究的是用Lua语言开发,但是学习起来还是蛮有趣的,我喜欢这种学习.下面基本的数学知识在Cocox的几种应用: 1.跳动的小球(向量的应用) local direction=cc.p(math.random(-1,1),math.random(-1,1)) cc.pNormalize(direction) local dot=display.newDrawNode():addTo(self):center(

codeforces#253 D - Andrey and Problem里的数学知识

这道题是这样的,给主人公一堆事件的成功概率,他只想恰好成功一件. 于是,问题来了,他要选择哪些事件去做,才能使他的想法实现的概率最大. 我的第一个想法是枚举,枚举的话我想到用dfs,可是觉得太麻烦. 于是想是不是有什么规律,于是推导了一下,推了一个出来,写成代码提交之后发现是错的. 最后就没办法了,剩下的时间不够写dfs,于是就放弃了. 今天看thnkndblv的代码,代码很短,于是就想肯定是有什么数学规律,于是看了一下, 果然如此. 是这样的,还是枚举,当然是有技巧的,看我娓娓道来. 枚举的话

window7使用svn(svn系列 客户端 知识二总结)

 ?eclipse插件subclipse  ?TortoiseSVN  ?svn操作  ?注意事项 使用svn可以在eclipse直接装subclipse或者在windows使用TortoiseSVN. 1.eclipse插件subclipse 可以在线或者离线安装,这里只介绍离线安装. 下载subclipse:http://subclipse.tigris.org/ csdn下载地址:http://download.csdn.net/detail/sinat_31719925/9800062