刘汝佳训练指南——数论专题知识点总结:

数论是一个神奇的东西,各种结论都很经典,有些懂,有些自己还不是很懂。

接下来就一个一个的介绍吧。

第一、素数,素数本身就是一个很让人惊奇的数,因为它代表的是唯一,自己就有连个因数,一个是1,一个是自己,因为1是每个数都具备的因子(除了0),所以,它也就相当于只有自己。是一个自我感觉很良好的人呀!

最朴素的算法当然是从2-sqrt(2)里面找因子,如果没有,就说明它是个素数。为什么到sqrt(n)?你想,sqrt(n)* sqrt(n)= n,而你因子的个数怎么算?是不是从1-sqrt(n)里面的因子数 * 2?显然可得,因子数是关于sqrt(n)对称的,这边有几个那边就有几个,所以枚举一般就行!

高深一点,有miller-robin,前面写过这个算法,但是好像不经常用,也就没去看过了。但是有一个是比较经常用的,那就是筛法欲求范围素数。这个思想运用广泛,euler函数里面也用到了这个思想。

贴出筛素数的算法,一会加上miller-robin:

[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <math.h>  
  4. #include <iostream>  
  5. #include <string>  
  6.   
  7. using namespace std;  
  8.   
  9. const int MAXN = 1000000 + 11;  
  10.   
  11. bool p[MAXN];  
  12.   
  13. int index[MAXN];  
  14.   
  15. void init()  
  16. {  
  17.     memset(p, 0, sizeof(p));  
  18.     p[0] = 1;  
  19.     p[1] = 1;  
  20.     for (int i = 4; i < MAXN; i += 2)  
  21.     {  
  22.         p[i] = 1;  
  23.     }  
  24.     int cnt = 0;  
  25.     index[cnt++] = 2;   
  26.     for (int i = 3; i < (int)sqrt(MAXN * 1.0); i += 2)  
  27.     {  
  28.         if (!p[i])  
  29.         {  
  30.             index[cnt++] = i;  
  31.             int k = i * 2;  
  32.             for (int j = k; j < MAXN; j += i)  
  33.             {  
  34.                 p[j] = 1;  
  35.             }  
  36.         }  
  37.     }  
  38.     /* 
  39.     for (int i = 0; i < cnt; i++) 
  40.     { 
  41.         printf("%d\n", index[i]); 
  42.     } 
  43.     */  
  44. }  
  45.   
  46. void sieve()//这是另外一种,这种看上去简单,但是和上面的思想是一摸一样的.   
  47. {  
  48.     int m = (int)sqrt(n + 0.5);  
  49.     for (int i = 2; i < m; i++)  
  50.     {  
  51.         if (!p[i])  
  52.         {  
  53.             for (int j = i * i; j < n; j += i)  
  54.             {  
  55.                 p[j] = 1;  
  56.             }  
  57.         }  
  58.     }  
  59. }  
  60.   
  61. int main()  
  62. {  
  63.     init();  
  64.     sieve();  
  65.     system("pause");  
  66.     return 0;  
  67. }  

二、欧几里德算法。欧几里德算法的精髓思想大概是辗转相除吧。还是比较好理解的,难点的就是扩展欧几里德算法,求a*x + b*y = gcd(a,b);这是一个解线性方程组的最佳算法。还有一个很好的应用就是求乘法逆元,这个应用很大,因为有很多时候因为数据量非常大,都会modulo一个素数。而逆元可以把除以一个数变成乘法,这个就比较好了。

贴出这些算法:

[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <iostream>  
  4. #include <string>  
  5.   
  6. using namespace std;  
  7.   
  8. typedef long long LL;  
  9.   
  10. void extgcd(LL a, LL b, LL &d, LL &x, LL &y)  
  11. {  
  12.     if (b == 0)  
  13.     {  
  14.         x = 1;  
  15.         y = 0;  
  16.         d = a;  
  17.     }  
  18.     else  
  19.     {  
  20.         extgcd(b, a % b, d, y, x);  
  21.         y -= x * (a / b);  
  22.     }  
  23.           
  24. }  
  25.   
  26. LL inv(LL a, LL n)  
  27. {  
  28.     LL d, x, y;  
  29.     extgcd(a, n, d, x, y);  
  30.     return d == 1 ? (x + n) % n : -1;  
  31. }  
  32.   
  33. int main()  
  34. {  
  35.     int ans = inv(2, 5);  
  36.     cout << ans << endl;  
  37.     system("pause");  
  38.     return 0;  
  39. }  

三、欧拉函数phi(n)。首先就要弄明白欧拉函数求得的含义:1-n之间和n互素的数的个数。公式是

phi(n) = n * (1 - 1 / p1) (1 - 1 / p2) (1- 1 / p3) (1 - 1 / p4)……

p1,p2,p3都是n素因数分解的素因数。有了这个公式就好办了。

现在贴出素因数分解的代码,其实在euler_phi函数里面就包含了这个思想,就是含有这个因子就把这个因子除尽。

素因数分解:

[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <math.h>  
  4. #include <iostream>  
  5. #include <string>  
  6.   
  7. using namespace std;  
  8.   
  9. int main()  
  10. {  
  11.     int N;  
  12.     while (scanf("%d", &N) != EOF)  
  13.     {  
  14.         int cnt = 0;  
  15.         cout << "N = ";  
  16.         for (int i = 2; i <= (int)sqrt(N + 0.5); i++)  
  17.         {  
  18.             if (N % i == 0)  
  19.             {  
  20.                 cout << i << "^";  
  21.                 while (N % i == 0)  
  22.                 {  
  23.                     N /= i;  
  24.                     cnt++;  
  25.                 }   
  26.                 cout << cnt << " ";  
  27.             }  
  28.         }  
  29.         if (N > 1)  
  30.         {  
  31.             cout << N << "^1";  
  32.         }  
  33.         cout << endl;  
  34.     }  
  35.     system("pause");  
  36.     return 0;  
  37. }   

接下来是euler_phi:

[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <math.h>  
  4. #include <iostream>  
  5. #include <string>  
  6. /* 
  7.  *首先你得清楚,欧拉函数的公式是什么: 
  8.  *推导出来的最简洁的公式是:phi(n) = n(1 - 1/p1)(1 - 1/p2)…… 
  9.  *这就可以轻松的求出来了  
  10.  *phi(n) 表示的含义是,不超过x且和x互素的整数个数.  
  11. */  
  12.   
  13. using namespace std;  
  14.   
  15. typedef long long LL;  
  16.   
  17. const int MAXN = 100000 + 11;  
  18.   
  19. int phi[MAXN];  
  20.   
  21. int euler_phi(int n)  
  22. {  
  23.     LL ans = n;  
  24.     for (int i = 2; i <= (int)sqrt(n + 0.5); i++)  
  25.     {  
  26.         if (n % i == 0)  
  27.         {  
  28.             ans = ans / i * (i - 1);  
  29.             while (n % i == 0)  
  30.             {  
  31.                 n /= i;  
  32.             }  
  33.         }  
  34.     }  
  35.     if (n > 1)  
  36.     {  
  37.         ans = ans / n * (n - 1);  
  38.     }  
  39.     return ans;  
  40. }  
  41.   
  42. void phi_table(int n)  
  43. {  
  44.     memset(phi, 0, sizeof(phi));  
  45.     phi[1] = 1;  
  46.     for (int i = 2; i <= n; i++) //因为要将所有的phi都求出来,所以要循环到n,因为有一些大于sqrt(n)   
  47.     {                            //的素数还没有求出结果;   
  48.         if (!phi[i])  
  49.         {  
  50.             for (int j = i; j < n; j += i)  
  51.             {  
  52.                 if (!phi[j])  
  53.                 {  
  54.                     phi[j] = j;  
  55.                 }  
  56.                 phi[j] = phi[j] / i * (i - 1);  
  57.             }  
  58.         }  
  59.     }  
  60. }  
  61.   
  62. void print(int n)  
  63. {  
  64.     for (int i = 1; i <= n; i++)  
  65.     {  
  66.         printf("phi[%d] = %d\n", i, phi[i]);  
  67.     }  
  68. }   
  69.   
  70. int main()  
  71. {  
  72. //  cout << "phi(i) = " << euler_phi(3) << endl;  
  73.     phi_table(30);  
  74.     print(30);  
  75.     system("pause");  
  76.     return 0;  
  77. }  

这只是最基本的算法,当然数论里面还有很多种算法,我会后续加上来的。


四、中国剩余定理。解决多个模方程,但是变量还是一个的问题,即x = a[i] (% m[i])。方法是令M为所有的m[i]的乘积,wi = M / mi,则gcd(wi, mi) = 1.使得wi * p + mi * q = 1,可以用extgcd求出来对于wi的p解,令e =  wi * pi,则方程组等价于方程x = e1*a1 + e2*a2 + e3*a3…… 且注意x是唯一解。

代码如下:

[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <iostream>  
  4. #include <string>  
  5. /* 
  6.  *中国剩余定理用与解决 x = a[i] (% m[i]); 
  7.  *而m[i]又每每互素,将会求的唯一的最小解。  
  8.  */   
  9.   
  10. using namespace std;  
  11.   
  12. typedef long long LL;  
  13.   
  14. const int MOD = 1000000000 + 7;  
  15.   
  16. void extgcd(int a, int b, int &d, int &x, int &y)  
  17. {  
  18.     if (b == 0)  
  19.     {  
  20.         d = a;  
  21.         x = 1;  
  22.         y = 0;  
  23.     }  
  24.     else  
  25.     {  
  26.         extgcd(b, a % b, d, y, x);  
  27.         y -= x * (a/ b);  
  28.     }  
  29. }  
  30.   
  31. int china(int n, int *a, int *m)  
  32. {  
  33.     int M = 0;  
  34.     int x, y, d;  
  35.     int ans = 0;  
  36.     for (int i = 0; i < n; i++)  
  37.     {  
  38.         M += m[i];  
  39.     }  
  40.     for (int i = 0; i < n; i++)  
  41.     {  
  42.         int w = M / m[i];  
  43.         extgcd(m[i], w, d, x, y);  
  44.         ans = ((LL)ans + (LL)y * w * a[i]) % MOD;  
  45.     }  
  46.     return (ans + MOD) % MOD;  
  47. }  
  48.   
  49. int main()  
  50. {  
  51.     system("pause");  
  52.     return 0;  
  53. }  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/382053.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第一次训练赛的相关总结和教训!

没有想到时间会不够用&#xff01;这是来到这里的真实感受&#xff0c;每天不停歇地看电脑&#xff0c;资料&#xff0c;刷题&#xff01;几乎没有停下过&#xff0c;有点喘不过气来&#xff0c;不过身体却有一种莫名的兴奋&#xff01; 不喜欢拖拉的人&#xff0c;可自己又总是…

goland中grpc的安装

go modules https://github.com/goproxy/goproxy.cn/blob/master/README.zh-CN.md go env -w GO111MODULEongo env -w GOPROXYhttps://goproxy.cn,direct安装 gRPC 网络环境允许的同学安装 gRPC 非常方便&#xff0c;直接执行以下命令即可安装完成&#xff1a; go get -u -v…

uva11029 - Leading and Trailing

11029 - Leading and TrailingTime limit: 3.000 seconds http://uva.onlinejudge.org/index.php?optioncom_onlinejudge&Itemid8&category115&pageshow_problem&problem1970Apart from the novice programmers, all others know that you can’t exactly rep…

goland远程调试Docker

开发环境 goland windows10 Docker centos IP:123.57.43.91 操作原理及流程 goland通过tcp/8080(应该选取2375&#xff0c;登录阿里云开启这个端口&#xff0c;这里临时采用)端口与docker-host通信&#xff0c; 发送docker指令&#xff0c;然后让linux执行&#xff0c;通过d…

博客同步测试

该博客通过word发布&#xff01;

gorm踩的坑

gorm的那些坑 1. db.SingularTable(true) 在Gorm中&#xff0c;表名是结构体名的复数形式&#xff0c;列名是字段名的蛇形小写。即&#xff0c;如果有一个user表&#xff0c;那么如果你定义的结构体名为&#xff1a;User&#xff0c;gorm会默认表名为users而不是user。 db.S…

Go 语言实现 23 种设计模式(修饰器)

修饰器 修饰器模式就是在不改变对象内部结构的情况下&#xff0c;动态扩展它的功能。 Example_one type Object func(string) stringfunc Decorate(fn Object) Object {return func(base string) string {ret : fn(base)ret ret " and Tshirt"return ret} }func…

紫书的训练计划——一点点来,坚持到底!

先做 第10章3 数论的一点补充。然后趁热温习 10.1 和10.2 &#xff08;可能会有重的题目&#xff09; &#xff08;期望&#xff0c;概率的题目还要过段时间回来补坑&#xff09;然后 第7、8.1&#xff0c;8.2 章做暴力求解和高效算法&#xff08;可以适当的加快步伐&#…

Go 语言实现 23 种设计模式 单例模式

Go 语言实现 23 种设计模式 单例模式 单例模式 单例模式是一种常用的软件设计模式&#xff0c;在使用过程中&#xff0c;单例对象的类只有一个实例。使用单例模式&#xff0c;1 可以节省内存等资源&#xff0c;例如windows操作系统的资源管理器只有一个就够了。2 方便配置管理…

Go 语言实现 23 种设计模式适配器

Go 语言实现 23 种设计模式适配器 将一个类型的接口转换成客户希望的另外一个接口&#xff0c;使原本由于接口不兼容而不能一起工作的类可以一起工作。 Example_one package mainimport "fmt"// Adaptee 适配者 type MyLegacyPrinter struct{}func (l *MyLegacyPr…

go设计模式思维导图

go设计模式思维导图

uva 1610——Party Games

题目链接&#xff1a;http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id51171 题意&#xff1a;给你n个串的集合D&#xff0c;然后求一个长度最短的串s&#xff0c;使得使得s大于等于D中一半的串&#xff0c;又同时小于另一半串。 思路&#xff1a;直接暴力。先对…

链表相加 2. 两数相加

2. 两数相加 给出两个 非空 的链表用来表示两个非负的整数。其中&#xff0c;它们各自的位数是按照 逆序 的方式存储的&#xff0c;并且它们的每个节点只能存储 一位 数字。 如果&#xff0c;我们将这两个数相加起来&#xff0c;则会返回一个新的链表来表示它们的和。 您可以…

uva10780 - Again Prime? No time

uva10780 - Again Prime? No timeAgain Prime? No time. The problem statement is very easy. Given a number n you have to determine the largest power of m, not necessarily prime, that divides n!. Input The input file consists of several test cases. The first…

303. 区域和检索 - 数组不可变

303. 区域和检索 - 数组不可变 给定一个整数数组 nums&#xff0c;求出数组从索引 i 到 j (i ≤ j) 范围内元素的总和&#xff0c;包含 i, j 两点。 示例&#xff1a; 给定 nums [-2, 0, 3, -5, 2, -1]&#xff0c;求和函数为 sumRange() sumRange(0, 2) -> 1 sumRange…

【转载】最短路径之Dijkstra算法详细讲解

&#xff11; 最短路径算法 在日常生活中&#xff0c;我们如果需要常常往返A地区和B地区之间&#xff0c;我们最希望知道的可能是从A地区到B地区间的众多路径中&#xff0c;那一条路径的路途最短。最短路径问题是图论研究中的一个经典算法问题&#xff0c; 旨在寻找图&#xf…

Intelij 添加php注释

没有methodParameters()) groovyScript("def result; def params\"${_1}\".replaceAll([\\\\[|\\\\]|\\\\s], ).split(,).toList(); for(i 0; i < params.size(); i) {result * param params[i] ((i < params.size() - 1) ? \\n:)}; return result…

HDU 2544 最短路(各种最短路算法的实现)

链接&#xff1a; http://acm.hdu.edu.cn/showproblem.php?pid2544 题目&#xff1a; Problem Description 在每年的校赛里&#xff0c;所有进入决赛的同学都会获得一件很漂亮的t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候&#xff0c;却是非常累的…

为什么LeetCode过一段时间又不会了

怎么从这个迷宫的左上角走到右下角&#xff1f; 看起来好像很简单&#xff0c;花时间还是可以找得到答案。 看了答案之后可以很清楚&#xff0c;这是正解。 只有一个问题&#xff1a; 我怎么就没立刻想到&#xff1f; 当在看题解或者听别人讲授思路的时候&#xff0c;你就是…

148. 排序链表

148. 排序链表 给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4] 示例 2&#xff1a; 输入&#xff1a;head [-1,5,3,4,0] 输出&#xff1a;[-1,0,3,4,5] 示…