您的位置:首页 > 其它

|算法讨论|数论数学 学习笔记

2017-02-01 12:11 239 查看
模板及讲解

欧几里得算法

求gcd(a, b),即a和b的最大公倍数

欧几里得算法:

gcd(a,b)=gcd(b,a%b)

int gcd(int a, int b)
{
if (b==0) return a;
gcd(b, a%b);
}


求ax+by=gcd(a,b)的解x,y

扩展欧几里得算法:

已求出下一个状态一组解x1,y1使得b⋅x1+(a%b)⋅y1=gcd(a,b)

由a%b=a−⌊ab⌋⋅b,得

b⋅x1+(a−⌊ab⌋⋅b)⋅y1=gcd(a,b)

b⋅x1+a⋅y1−b⋅y1⋅⌊ab⌋=gcd(a,b)

a⋅y1+b⋅(x1−y1⋅⌊ab⌋)=gcd(a,b)

对照ax+by=gcd(a,b),可得

x=y1,y=x1−y1⋅⌊ab⌋

由欧几里得算法终止条件a=gcd(a,b),b=0得,a∗1+b∗0=gcd(a,b)

所以x,y的边界值是1,0

通解:

⎧⎩⎨⎪⎪⎪⎪⎪⎪x=x0+bgcd(a,b)∗ty=y0–agcd(a,b)∗t

int egcd(int a, int b, int &x, int &y)
{
if (b==0)
{
x = 1;
y = 0;//边界值
return a;//求最大公倍数
}
int temp = x;
int ans = egcd(b,a%b,x,y);
x = y;
y = temp-y*a/b;//公式计算
return ans;
}


求不定方程ax+by=c的最小一组解x,y:

先求出g=gcd(a,b)

如果c%g≠0,无解

否则,将不定方程两边同时除以g,得a1x+b1y=c1

此时gcd(a1,b1)=1,可用扩展欧几里得算法求出a1x1+b1y1=1的解x1,y1

即a1x+b1y=c1的一组解为x1⋅c1,y1⋅c1

求最小解可用一组特解模b即可得到

求a 关于 m 的乘法逆元

ax≡1(modn)

由同余性质得,ax−1=ny

变形,得 ax−ny=1,此时gcd(a,n)必须为1且只有唯一解, 否则无解

即可使用扩展欧几里得算法求解

中国剩余定理

设正整数m1,m2,...,mk两两互素,则同余方程组

⎧⎩⎨⎪⎪⎪⎪⎪⎪xxx≡≡≡a1a2ak(modm1)(modm2)⋮(modmk)

有整数解。并且在模M=m1⋅m2⋅...⋅mk下有唯一解,

解为

x≡(a1M1M−11+a2M2M−12+...+akMkM−1k)(modM)

其中Mi=Mmi,M−1i是Mi模mi下的逆元

解法:先O(n)的时间求出M,然后求出Mi, 用扩展欧几里得算法求出M−1i,根据公式进行计算

int crt(int n, int *a, int *m)
{
int ans = 0;
int M = 1;
for (int i=1;i<=n;i++) M *= m[i];
for (int i=1;i<=n;i++)
{
int Mi = M/m[i];
int x,y;
e_gcd(Mi, m[i], x, y);//求Mi的逆元x
ans = (ans + a[i]*Mi*x)%M;
}
return (ans+M)%M;
}


筛选法求质数

int vis
;
int sx()
{
int m = sqrt(n+0.5);
ms(vis,0);
for (int i=2;i<=n;i++)
if (!vis[i]) for (int j=i*i;j<=n;j+=i) vis[j] = 1;
}


欧拉函数

给出n的唯一分解式 n=pa11pa22pa33...pakk , 求出 1,2,3...,n 中与n互素的数的个数

公式(容斥原理): φ(n)=∑S⊆(p1,p2,...pk)(−1)|s|n∏pi⊆Spi

可变形为:φ(n)=n(1−1p1)(1−1p2)...(1−1pk)

即可在O(k)的时间复杂度算出φ(n)

不给出唯一分解式求φ(n):

根据变形的公式,可以枚举所有小于n√的因子,然后之后把他”除干净”即可

int phi(int n)
{
int ans = n;//ans为最后的答案
int m = (int)sqrt(n+0.5);
for (int i=2;i<=m;i++) if (n%i==0)
{
ans = ans/i*(i-1);//ans初值为n,因为1-(1/p) = (p-1)/p,由变形后公式可得
while (n%i==0) n/=i;//除干净
}
if (n>1) ans = ans/n*(n-1);
return ans;
}


用筛选法在O(nloglogn)时间复杂度求1~n中所有数的欧拉phi函数值:

int phitable(int n, int* phi)
{
for (int i=2;i<=n;i++) phi[i] = 0;
phi[1] = 1;
for (int i=2;i<=n;i++) if (!phi[i])
for (int j=i;j<=n;j+=i)
{
if (!phi[j]) phi[j] = j;
phi[j] = phi[j]/i*(i-1);
}
}


求正约数的个数

给出n的唯一分解式 n=pa11pa22pa33...pakk , 求出 n 的正约数的个数

根据乘法原理,n 的正约数的个数为

∏i=1k(ai+1)

快速幂

int fastpow(int a,int b)
{
int ans=1,base=a;
while(b!=0){
if(b&1!=0)
ans*=base;
base*=base;
b>>=1;
}
return ans;
}


排列

一般地,从n个不同元素中取出m(1≤m≤n)个元素,按照一定的顺序排成一列,叫做从n个元素中取出m个元素的一个排列(顺序不同是不同的两种方案)

(约定0!=1)

1 无重排列

从n个不同元素中有序且不重复取出k(1≤k≤n)个元素,称为n个不同元素中取出k个元素的一个无重排序,简称k-排列,所有这样的排列个数记为Akn

Akn=n!(n−k)!

2 全排列

(1) 无重

当k-排列中的k=n时

Ann=n!

3 重复排列

从n个不同元素中有序且可重复取出k(1≤k≤n)个元素,称为n个不同元素中取出m个元素的一个无重排序,简称k-可重排列

重复排列个数为

nk

4 圆周排列

从n个不同元素中无重复地取出k(1≤k≤n)个元素排在一个圆周上,称为n个不同元素的一个圆周排列,简称k-圆排列

圆周排列个数为

Pknk=n!k⋅(n−k)!

组合

一般地,从n个不同元素中取出m(1≤m≤n)个元素组成一组,叫做从n个元素中取出m个元素的一个组合(顺序不同是相同的两种方案)

(约定0!=1)

1 无重组合

从n个不同元素中无序且不重复取出k(1≤k≤n)个元素,称为n个不同元素中取出k个元素的一个无重组合,简称k-组合,所有这样的排列个数记为Ckn

Ckn=Aknk!=n!k!(n−k)!

2 重复组合

从n个不同元素中无序但可重复取出k(1≤k≤n)个元素,称为n个不同元素中取出k个元素的一个重复组合,简称k-可重组合

重复组合个数为

Ckn+k−1=(n+k−1)!k!(n−1)!

概率

1 数学期望

随机变量X的数学期望E(X)就是所有可能值按照概率加权的和。

E(X)=∑i=1nxipi
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: