本次内容包括:快速幂,拓展欧几里得,同余逆元,埃氏筛法
快速幂
背景:求a的n次幂
常规方法:循环累乘 复杂度O(n)
数论方法:快速幂,使用二进制拆分或分治。复杂度对数级
二进制拆分:将n从二进制角度去看,不断二进制右移,当末位为1则乘,每次右移都会改变乘数1 2 4 8。
代码:
int fastpow(int a,int n)
{
int base=a;
int ans=1;
while(n)
{
if(n&1)
{
ans*=base;
}
base*=base;
n>>=1;
}
}
或者有
int fastpow(int a,int n)
{
int ans=1;
while(n)
{
if(n&1)
{
ans*=a;
}
a=fastpow(a,a)
n>>=1;
}
}
分治:层层拆分后分堆合并。
代码:
int fastpow(int a,int n)
{
int temp;
if(n==1)
return a;
temp=fastpow(a,n/2);
if(n&1)
return temp*temp*a;
return temp*temp;
}
temp=fastpow(a,n/2);
注意这一步
拓展:矩阵快速幂
重点:将矩阵视为同快速幂中的整数元素即可。
主要操作有:定义矩阵乘法,初始化矩阵,设置单位矩阵。
0.
初始化矩阵
struct matrix
{
int m[50][50];
matrix()
{
memset(m,0,sizeof(m));
}
};
1.矩阵乘法线性代数有学不再说明:
Matrix multi(matrix a,matrix b)//乘法二元操作
{
matrix res;
for(int i=0;i<50;i++)
{
for(int j=0;j<50;j++)
{
for(int k=0;k<50;k++)
{
res.m[i][j]+=a.m[i][k]*b.m[k][j];//从左向右,分行乘列,层层进行
}
}
}
return res;
}
2.设置单位矩阵与矩阵快速幂
int fastpow(matrix a,int n)
{
matrix res;
for(int i=0;i<50;i++)
res.m[i][i]=1;
while(n)
{
if(n&1)
Matrixmulti(res,a);
a=Matrixmulti(a,a);
n>>=1;
}
return res;
}
拓展欧几里得
四步走,我之前有写,不再写了。
同余逆元
同余: a和b取模于m的余数相同,成为同余。
性质:a-b是m的整数倍
应用:构成二元一次方程ax+by=mn
逆元: ax和1取模于m同余。得到ax-my=1,得到ax+my=1视m为参数,加号可允许m可正可负
,得到二元一次方程之后,用拓展欧几里得求解的得出逆元
代码:
int inverse(int a,int b)
{
int x,int y;
exgcd(a,m,x,y);
return (m+x%m)%m;//a模m的逆
}
应用:逆元与除法取模
a,b,k设k是b的逆元
则对于(a/b)%m=ak%m
求二元一次方程
如果知道了a的逆,那么可求ax与b取模m同余的方程,
设a的逆为k
x与k*b取模于m同余。
埃氏筛法
思想:找从2到n所有的素数,从头开始,2是最小的素数,然后把2-n中所有2的倍数删去,下一个素数是3,把所有3的倍数删去。
实操:删除操作可以用单链表,也可以用标记数组来完成。