数论 素数筛选法与整数的素因子分解

数论


数论是最原始的两个数学分支,即算术几何,保留下来的问题。传统的几何学已经凋零,所有的问题都得到解决。而传统的算术却积累了越来越多的问题,成为难以穿越的密林。过去被认为是纯粹数学的,是专门研究整数的性质,正整数按乘法性质划分,可以分成“素数”,“合数”,“1”,素数产生了很多一般人也能理解而又悬而未解的问题,如哥德巴赫猜想。很多问题虽然形式上十分初等,但事实上却要用到许多艰深的数学知识。这一领域的研究从某种意义上推动了数学的发展,催生了大量的新思想和新方法。

卡尔·弗里德里希·高斯曾说:“数学是科学的皇后,数论是数学的皇后。”

[编辑]
数论早期铺垫有三大内容:
数论初期的铺垫工作

  1. 欧几里得证明素数无穷多个。
  2. 寻找素数的埃拉托斯特尼筛法;欧几里得求最大公约数的辗转相除法
  3. 公元420至589年(中国南北朝时期)的孙子定理

以上工作成为现代数论的基本框架。

[编辑]数论中期工作

数论从早期到中期跨越了1000—2000年,在接近2000年时间,数论几乎是空白。中期主要指15-16世纪到19世纪,是由费马,梅森,欧拉,高斯,勒让德黎曼,希尔伯特等人发展的。

内容是寻找素数通项公式为主线的思想,开始由初等数论向解析数论代数数论转变,产生了越来越多的猜想无法解决,遗留 到20世纪,许许多多的困难还是依赖素数通项公式,例如黎曼猜想素数公式。如果找到一个素数通项公式,现在一些困难问题 就可以由解析数论转回到初等数论范围。

[编辑]分支

初等数论
意指使用不超过高中程度的初等代数处理的数论问题,最主要的工具包括整数的整除性与同余。重要的结论包括 中国余数定理费马小定理二次互反律等等。
解析数论
借助 微积分复分析的技术来研究关于整数的问题,主要又可以分为 积性数论加性数论两类。积性数论借由研究积性生成函数的性质来探讨质数分布的问题,其中 质数定理狄利克雷定理为这个领域中最著名的古典成果。加性数论则是研究整数的加法分解之可能性与表示的问题, 华林问题是该领域最著名的课题。此外例如 筛法圆法等等都是属于这个范畴的重要议题。
代数数论
引申 代数数的话题,关于 代数整数的研究,主要的研究目标是为了更一般地解决 不定方程的问题,而为了达到此目的,这个领域与 代数几何之间有相当关联,比如 类域论(class field theory)就是此间的颠峰之作。
算术代数几何
研究有理系数多变量方程组的有理点,其结构(主要是个数)和该方程组对应的代数簇的几何性质之间的关系,有名的 费马最后定理Mordell猜想Weil猜想,和千禧年大奖难题中的 贝赫和斯维讷通-戴尔猜想都属此类。
几何数论
主要在于透过几何观点研究整数(在此即格子点)的分布情形。最著名的定理为 闵可夫斯基定理
计算数论
借助电脑的 算法帮助数论的问题,例如素数测试和 因子分解等和 密码学息息相关的话题。
超越数论
研究数的超越性,其中对于 欧拉常数与特定的Zeta函数值之研究尤其令人感到兴趣。
组合数论
利用组合和机率的技巧,非构造性地证明某些无法用初等方式处理的复杂结论。这是由 保罗·埃尔德什开创的思路。
模形式







筛选法   

     求出n以内的素数,最快的应该是筛选法。

 筛选法的思路是:

     要求10000以内的素数,把1-10000都列出来,1不是素数,划掉;2是素数,所有2的倍数都不是素数,划掉;取出下一个幸存的数,划掉它的所有倍数;直到所有素数找完为止。

     这种做法的空间复杂度是O(n),时间复杂度O(n/logn)。

Cpp代码   收藏代码
  1. const int Max = 1000005;  
  2. bool prime[Max]={0};//0表示素数,1为非素数  
  3.   
  4. //筛选n以内的素数  
  5. void getPrime(int n)  
  6. {  
  7.     int i,j;  
  8.     int t;  
  9.     for(i = 2; i <= n; i++)  
  10.     {  
  11.         if(!prime[i])  
  12.         {  
  13.             for(j = 2; (t=j*i) <= n; j++)  
  14.                 prime[t] = 1;  
  15.         }  
  16.     }  
  17. }  

 

 

 

 

分解素因子

     唯一质因子分解定理:任意一个合数a仅能以一种方式,写成如下的乘积形式:

a = p1^e1*p2^e2*...*pr^er

    其中pi为素数,p1<p2<...<pr,且ei为正整数。例如数6000=2^4*3*5^3。

    素因子的分解技巧:首先a的某两个素因子不可能同时大于sqrt(a),这样,先用筛选法求出sqrt(a)以内的所有素数,然后用a依次去mod这些素数,若能整除,则找到素因子,将素因子去掉,再继续找。最后若a>1,则a也是它的素因子。

 

Cpp代码   收藏代码
  1. const int Max = 100005;  
  2. int isPrime[Max]={0};  
  3. int prime[Max/5],num=0;  
  4. int factors[100],s=0;  
  5.   
  6. void getPrime(int n)  
  7. {  
  8.     int i,j;  
  9.     int t;  
  10.     for(i = 2; i <= n; i++)  
  11.     {  
  12.         if(!isPrime[i])  
  13.         {  
  14.             prime[num++] = i;  
  15.             for(j = 2; (t=i*j) <= n; j++)  
  16.                 isPrime[t] = 1;  
  17.         }  
  18.     }  
  19. }  
  20.   
  21. void decompose(int n, int* factors)  
  22. {  
  23.     int te = (int)sqrt(n*1.0);  
  24.     for(int i = 0; i<num&&prime[i]<=te; i++)  
  25.     {  
  26.         if(n%prime[i]==0)  
  27.         {  
  28.             factors[s++] = prime[i];  
  29.             while(n%prime[i]==0)  
  30.                 n = n/prime[i];  
  31.         }  
  32.     }  
  33.     if(n > 1)  
  34.         factors[s++] = n;  
  35. }  

 

 

POJ2262

题意:给出任意一个正整数n(n<=10^6),根据哥德巴赫猜想:任意一个不小于6的整数,都可以表示为两个奇素数之和。问虽任意整数是否满足这个猜想。

解:筛选法将n以内的所有素数都求出来,若a是素数,判断n-a是否为素数,若找到一组不满足,则答案为否定。

 

POJ1142

题意:给一个数n(n<=10^7),求最小的m>n,使得m的素因子每一位上的数的和 == m的每一位上的数的和。

解:显然这题就是要分解素因子。先求10^4以内的素数,再用素因子分解,然后判断。

 

Cpp代码   收藏代码
  1. #include <iostream>  
  2. #include <cstdio>  
  3. #include <cstring>  
  4. #include <cmath>  
  5. using namespace std;  
  6. const int Max = 10005;  
  7. bool isPrime[Max]={0};  
  8. int prime[Max/4],num=0;  
  9.   
  10. void getPrime(int n)  
  11. {  
  12.     int t;  
  13.     for(int i = 2; i <= n; i++)  
  14.     {  
  15.         if(isPrime[i]==0)  
  16.         {  
  17.             prime[num++] = i;  
  18.             for(int j = 2; (t=j*i) <= n; j++)  
  19.                 isPrime[t] = 1;  
  20.         }  
  21.     }  
  22. }  
  23.   
  24. int getSum(int n)  
  25. {  
  26.     int ret = 0;  
  27.     while(n)  
  28.     {  
  29.         ret += n%10;  
  30.         n /= 10;  
  31.     }  
  32.     return ret;  
  33. }  
  34.   
  35. bool isSmith(int n)  
  36. {  
  37.     int t = (int)sqrt(n*1.0);  
  38.     int r1 = getSum(n);  
  39.     int r2 = 0;  
  40.     int N = n;  
  41.     for(int i = 0; i<num&&prime[i]<=t; i++)  
  42.     {  
  43.         if(n%prime[i]==0)  
  44.         {  
  45.             int tmpt = getSum(prime[i]);  
  46.             while(n%prime[i]==0)  
  47.             {  
  48.                 n = n/prime[i];  
  49.                 r2 += tmpt;  
  50.             }  
  51.         }  
  52.     }  
  53.     if(n > 1)  
  54.         r2 += getSum(n);  
  55.     if(n==N)  
  56.         return false;  
  57.     return r1==r2;  
  58. }  
  59.   
  60. int main()  
  61. {  
  62.     int i;  
  63.     int n;  
  64.     getPrime(Max-1);  
  65.     while(true)  
  66.     {  
  67.         scanf("%d",&n);  
  68.         if(!n)  
  69.             break;  
  70.         for(i = n+1; ;i++)  
  71.         {  
  72.             if(isSmith(i))  
  73.                 break;  
  74.         }  
  75.         printf("%d\n",i);  
  76.     }  
  77.     return 0;  
  78. }  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值