数学算法模板总结
2017-04-01 11:44
218 查看
数学算法模板总结
素数
素数可以说是组成一个数的基本单位,关于素数的算法有线性筛素数,唯一分解定理与素数快速判断,这里来介绍一下线性筛素数的算法。线性筛素数
void prim() { bool su[MAXN]; int sn[MAXN],num,n,t; su[0]=1;su[1]=1; for(int i=2;i<=n;i++) { if(!su[i]) sn[++num]=i; for(int j=1;sn[j]*i<=n&&j<=num;j++) { su[i*sn[j]]=1; if(!(i%sn[j])) break; } } }
这个算法可以说”几乎”是的O(n)的,虽然程序看上去并不是。
这个算法保证了每个合数只被筛了一次。
因为这种算法保证每一个合数由其最小的素数和一个最大的合数筛去的。
if(!(i%sn[j]))break;
我们可以这样理解。i=p(a的最小质因子)*a(一个合数)。
如果i%sn[j]==0,那么p*a*sn[k+1] 可以被后面的a*prime[k+1]再与p筛出来。
因为p < sn[j+1], 所以再这时应该停止。
素数快速判断 Miller-Rabin算法
Miller-Rabin算法随机生成底数a,进行多次调用函数进行测试,Miller-Rabin检测也存在伪素数的问题,但是与费马检测不同,MR检测的正确概率不依赖被检测数p,而仅依赖于检测次数。已经证明,如果一个数p为合数,那么Miller-Rabin检测的证据数量不少于比其小的正整数的3/4,换言之,k次检测后得到错误结果的概率为(1/4)^k。我们在实际应用中一般可以测试15~20次。
欧几里德算法&&扩展欧几里德算法
欧几里德算法也叫辗转相除法,可以证明,gcd(a,b)=gcd(b,a%b)而扩展欧几里德算法,就是在求gcd的回推的基础上求出方程ax+by=gcd(a,b) 的一个特征解。于是,我们就可以用其来解/判断是否有解一个二元不定方程了。
int e_gcd(int a,int b,int& x,int& y) { if(!b) return x=1,y=0,a; int ans=e_gcd(b,a%b,y,x); return y-=a/b*x,ans; }
我们也可以用其求逆元,在下面会提到。
逆元
因为mod不满足除法,所以我们需要用到逆元来求a/b的模数。逆元就相当与(1/b)mod p逆元有两种求法。第一种就是用扩展欧几里德来求解。
我们有同余方程
ax≡1(modp)
如果有解,x就算a模p意义下的逆元。
可以变成
ax−yp=1
用扩展欧几里德来求解。
线性筛逆元
其实还有线性的方法筛出**质素**p的逆元。
我们设
1−1≡1(modp)
设 p=x∗a+r,r<a,1<i<p
有我们知道
p≡0(modp)=>x∗a+r≡0(modp)
两边同时乘以a−1∗r−1得到
x∗r−1+a−1≡0(modp)
整理得
a−1≡−x∗r−1(modp)
a−1≡−⌊pa⌋∗(pmoda)−1(modp)
代码
a[1]=1; for(int i=2;i<p;i++) a[i]=-(p/i)*a[p%i];
BSGS
BSGS(baby step giant step)就是求同余方程ax≡b(modp)
我们设x=im−j,将其带入式子可以得到
aim−j≡b(modp)
即 aim≡b∗aj(modp)
我们可以计算b∗ajmodp(i=0 to m)的值(快速幂) 将其放入map中 map[b∗ajmodp]=j
之后再枚举a的im次mod p的值,如果发现再map有对应解
ans=m∗i−map[aimmodp]
可以证明,当m=p‾‾√最快。
为什么x=im−j,即x的最大值不超过p.
有公式即 ak%p−1≡ak(modp)(当a与p互质),通过小费马证得。
k可以看成k−m(p−1) 于是上面的式子变成了
ak(a(p−1))m≡ak(modp)
由于小费马,ap−1≡1(modp),可以得到
ak1m≡ak(modp)
这样就确保了x比p小。
LL BSGS(LL y,LL z,LL p) { map<LL,LL> ma; LL m=sqrt(p),tmp=0; ma.clear(); if(y%p==0&&z==0) return 1; if(y%p==0&&z!=0) return -1; for(int i=0;i<=m;i++) { if(!i) {tmp=z%p;ma[tmp]=i;continue;} tmp=(tmp*y)%p; ma[tmp]=i; } tmp=1;LL t=power(y,m,p); for(int i=1;i*i<=p;i++) { tmp=(tmp*t)%p; if(ma[tmp]) { LL ans=i*m-ma[tmp]; return ans; } } return -1; }
扩展BSGS
如果p不一定是素数,可以这样
我们设c=gcd(ax,p)
可以得到
axc≡bc(modpc)
设x=k+i 使得gcd(ai,p)=c
这样就可以用BSGS求ak模cd下逆元。
欧拉函数ϕ(x)
ϕ(x)表示不超过正整数x的数中与x互质的数的个数。引理1
1.如果p为素数ϕ(p)=p−1
2.如果n为素数p的x次方ϕ(n)=ϕ(pa)=(p−1)∗pa−1
2.如果n=i*p,p为素数,且i%p==0 ϕ(n)=p∗ϕ(i)
2.如果n=i*p,p为素数,且i%p!=0 ϕ(n)=(p−1)∗ϕ(i)
3.如果n为素数a与素数b的乘积ϕ(n)=ϕ(a∗b)=ϕ(a)∗ϕ(b)
引理2
n拆分乘pa11∗pa21∗pa31∗pa41∗.....∗pakk的素数幂乘积的表达式
ϕ(n)=n∗(1−1p1)∗(1−1p2)∗(1−1p3)∗......∗(1−1pk)
线性筛欧拉
因为上面的引理1,我们可以在筛素数的同时筛出欧拉。
#include <iostream> #include <cstring> using namespace std; const int MAXN = 1e6+5; bool su[MAXN]; int sn[MAXN],num,n,t; int phi[MAXN]; void Get_phi() { su[0]=1;su[1]=1;phi[1]=1; for(int i=2;i<=MAXN;i++) { if(!su[i]) sn[++num]=i,phi[i]=i-1; for(int j=1;sn[j]*i<=MAXN&&j<=num;j++) { su[i*sn[j]]=1; if(!(i%sn[j])) { phi[i*sn[j]]=phi[i]*sn[j]; break; } phi[i*sn[j]]=phi[i]*(sn[j]-1); } } } int main() { Get_phi(); return 0; }
欧拉定理
如果a与m互质,则aϕ(m)≡1(modb)
相关文章推荐
- 【算法总结-数学】求1-N中1出现的次数
- 算法总结之几何模板
- 【总结】DFS算法模板及题型分类
- 关于最短路的几种算法的模板总结
- lambda与算法模板学习总结
- pku数学类算法题目总结
- 数学建模算法总结(三)
- 数学建模算法总结(二)
- STL + c++ + 模板 + 重要思维 + 基础算法+ 经典算法 + 经典实例 + 编程总结+ 心得+ 入门必会 + 知识点汇总。+string +dfs +bfs等重要算法
- 【算法小总结】母函数模板
- 图论常用算法之二 算法模板及建模总结
- 数学建模学习笔记(建模中的十大常用算法总结)
- 算法核心思想总结及模板(不定期更新)
- 青蛙的约会【数学算法总结】
- [设计模式总结] 7. 模板方法模式 -封装算法
- hihocoder #1068 : RMQ-ST算法 ( RMQ算法 O(nlogn)处理 O(1)查询 *【模板】 1)初始化d数组直接读入+计算k值用数学函数log2()==*节约时间 )
- ACM经典算法之数学问题模板
- 计算几何常用算法总结-【数学】
- 【算法总结】组合数学相关
- 数学建模算法总结(一)