NOI前总结:数论(素数部分)

说到素数不得不说素数判定算法。

其中极为经典的为Rabin Miller测试。

通过二次探测的方法,我们可以将其正确率上升到一个很高的高度。

二次探测的原理我还是不太懂,所以NOI前我暂时只是梳理一下这个算法的流程。

首先,我来介绍一些小Trick。

$O(1)$的快速乘。

在一些卡常数而且爆long long的取余问题中我们常常要用到快速乘。

朴素的快速乘是$O(logn)$的,从而添加了不必要的复杂度。

在这里介绍$O(1)$的快速乘。

在 c++ 运算中,有的时候是会爆long long的,但它实质上是对于$0x7ffffffffffffff$取余的结果,这就为我们创造了良好的性质

在long long运算中我们只要不涉及除法,那么他一直是对INF取余的结果,对答案没有干扰。

所以代码就很好理解了:

1 LL mul(LL a,LL b,LL mod){
2     if(a<=(LL)(1e8) && b<=(LL)(1e8)) return a*b%mod;
3     return (a*b - (LL)(a/(LD)mod*b + 1e-3)*mod + mod) % mod;
4 }

注意快速乘在很小的数字时可能出错,所以特判一下。

注意一下Linux下rand()函数足够大,不需要我们去拓充。

转入正题:Rabin测试。

我的Rabin在INT范围内不会出错,在LOGN LONG范围内出错的概率极低。

首先是写一个check(LL x,LL P),用数字x检验P是否为素数。

 1 bool check(LL x,LL P){
 2     LL tmp=P-1;
 3     while(!(tmp&1)) tmp>>=1;
 4     LL m=qpow(x,tmp,P);
 5     if(m==1) return 1;
 6     while(tmp<P){
 7         if(m==P-1) return 1;
 8         tmp<<=1; m=mul(m,m,P);
 9     }
10     return 0;
11 }

完了又要死记 TAT。

梳理一下过程

首先将P-1中所有的2全都除掉。

这时候如果tmp 为 P-1 或者 1是伪素数。(具体就用 $x^{tmp} = 1 (mod P)$判定)

这时候检查$x^{2tmp} , x^{4tmp}, x^{8tmp} ....$是否等于 $P-1$。

如果没有则说明P不是素数。

接下来基于这一个$O(logn)$判定素数,我们有$O(n^{1/4})$的分解质因数算法。

Rho算法。

Rho算法是基于一个定理对于一个小于n的数字x如果 $(x,n) ≠ 1$ 则有,(x,n)为n的因子。

这样我们只要考虑怎样高效地得到这样的数字x。

 1 LL Rdo(LL n,LL c){
 2     LL i=1,k=2,x,y,d,p;
 3     x=Rand()%n;
 4     y=x;
 5     while(1){
 6         i++;
 7         x=(mul(x,x,n)+c)%n;
 8         if(y==x) return n;
 9         p=Abs(x-y);
10         d=gcd(p,n);
11         if(d!=1&&d!=n) return d;
12         if(i==k){
13             y=x;
14             k+=k;
15         }
16     }
17 }
18
19 int tot;
20 LL a[N];
21
22 void down(LL n){
23     if(n==1) return;
24     if(isprime(n)){
25         a[++tot]=n;
26         return;
27     }
28     LL t=n;
29     while(t==n) t=Rdo(n,Rand()%(n-1)+1);
30     down(t);
31     down(n/t);
32 }

Rdo() 主要是返回一个n的因子的,好像有证明通过上面那种方法最后是一个Rdo形状。

这样我们就可以得到了分解质因数的高效方法。

注意一个数字的质因子最多有$O(logn)$个,因为质因数的乘积为n,而且质因数都大于1.

继续,某天SB PHX在B站上随便找题。

找到了这样一道题:

给定一个整数N,求N最少可以拆成多少个完全平方数的和。

贪心??

然而数据范围:

30.的数据N≤10^6  
60.的数据N≤10^9 
100.的数据0≤N≤10^18 ,TEST<=1000

显然是让$O(logn)$的样子

所以根据拉格朗日平方和定理,答案为1~4

答案为1,直接SB 开方验证

答案为2,根据勾股数定理一个数字为勾股数当且仅当其质因数分解中所有的$4n+3$项的指数为偶数。(具体证法百度“勾股数”,基本上就是同余和欧几里得的知识)

答案为3,根据初等数论中的不等式 $n ≠ (8k + 7)  \cdot 4^{m}$

不然答案为4,根据 拉格朗日平方和定理即可。

Rank1 好开心 o(>_<)o

时间: 2024-12-29 09:38:08

NOI前总结:数论(素数部分)的相关文章

HDU4497 GCD and LCM 数论 素数分解

题意很简单首先以前做最简单的LCM跟CGD的时候都知道先求出两个数A,B的最大公约数GCD,那么LCM可以利用  A*B/GCD来求得,这点一开始脑残了没想到,结果没有进行特盘所以错了,意思就是 题目给的L%G不为0的话就是无解,结果我给判其它的去了,肯定漏了些什么没有发现 然后对于 L/G进行素因子分解,同时任意的数都能够通过素因子分解来表示,所以三个解x,y,z也能分解 L/G = p1^q1*p2^q2.... x = p1^i1*... y = p1^j1*... z = p1^k1*.

求前n个素数(C++)

输入一个输n,输出前n个素数. 1 #include<iostream> 2 #include <math.h> 3 using namespace std; 4 5 class Sushu 6 { 7 public: 8 9 Sushu() 10 { 11 num = 2; 12 } 13 14 ~Sushu() 15 { 16 } 17 18 bool isSushu() 19 { 20 for (int i = 2; i <=sqrt(num); i++) 21 { 2

NOI前训练记录

从今年年初开始就没怎么碰oi,学了三个月文化课,然后就是省选到处跑(浪),进了省队后又去北京打(浪)了波(七)铁(天),回家后又生了一星期病,感觉自己noi凉透了... ctsc因为运气的原因有人放弃D3自己才拿到au,apio什么牌都没拿到,自己这么菜的主要原因可能还是没怎么做题吧,五个月不碰oi,已经连dfs都不会了,还有两个月就noi了,再不训练又要为JS丢脸了,自己拿不到au却占了个省队名额,而阿老师邀请赛冠军的水平却没进省队,感觉自己不珍惜这个省队名额真的是说不过去 本文就记录一下本人

数论-素数

    素数定义: 质数(prime number)又称素数,有无限个.质数定义为在大于1的自然数中,除了1和它本身以外不再有其他因数,这样的数称为质数.例 子:2.3.5.7.11.13.17.19. 素数一些性质: 质数p的约数只有两个:1和p: 任一大于1的自然数,要么本身是质数,要么可以分解为几个质数之积,这种分解是唯一的: 一个偶数可以写成两个合数之和,其中每一个合数都最多只有9个质因数: 一个偶数必定可以写成一个质数加上一个合成数,其中合数的因子个数有上界: 素数应用: 数学上来看,

NOI前总结:点分治

点分治: 点分治的题目基本一样,都是路径计数. 其复杂度的保证是依靠 $O(n)$ 找重心的,每一次至少将问题规模减小为原先的$1/2$. 找重心我喜欢$BFS$防止爆栈. 1 int Root(int x){ 2 dfsn[0]=0; 3 q.push(x); fa[x]=0; 4 flag[x]=1; 5 while(!q.empty()){ 6 int x=q.front(); q.pop(); 7 dfsn[++dfsn[0]]=x; 8 for(int i=g[x];i;i=E[i].

数论 - 素数的运用 --- poj 2689 : Prime Distance

Prime Distance Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 12512   Accepted: 3340 Description The branch of mathematics called number theory is about properties of numbers. One of the areas that has captured the interest of number th

hdu 4497 GCD and LCM 数论 素数分解

GCD and LCM Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total Submission(s): 1339    Accepted Submission(s): 607 Problem Description Given two positive integers G and L, could you tell me how many solutions of

总结:数论 素数

素数判定算法,经典的Rabin Miller测试,通过二次探测的方法,可以将其正确率上升到一个很高的高度. $O(1)$的快速乘. 在一些卡常数而且爆long long的取余问题中用到快速乘. 朴素的快速乘是$O(logn)$的,从而添加了不必要的复杂度. 爆long long的,实质上是取余的结果,在long long运算中只要不涉及除法,那么一直是对INF取余的结果,对答案没有干扰. 1 LL mul(LL a,LL b,LL mod){ 2 if(a<=(LL)(1e8) &&

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

筛选法 求出n以内的素数,最快的应该是筛选法. 筛选法的思路是: 要求10000以内的素数,把1-10000都列出来,1不是素数,划掉:2是素数,所有2的倍数都不是素数,划掉:取出下一个幸存的数,划掉它的所有倍数:直到所有素数找完为止. 这种做法的空间复杂度是O(n),时间复杂度O(n/logn). 1 const int Max = 1000005; 2 bool prime[Max]={0};//0表示素数,1为非素数 3 4 //筛选n以内的素数 5 void getPrime(int n