朴素欧几里得
用途:求公约数
//手写版
int gcd(int a,int b){
if(b==0)return a;
return gcd(b,a%b);
}
//系统函数版
int ans=__gcd(a,b);
扩展欧几里得
用途:解不定方程ax+by==gcd(a,b)的一组整数解
int exgcd(int a,int b,int &x,int &y){
if(b==0){x=1,y=0;return a;}
int xx,yy,d;
d=exgcd(b,a%b,xx,yy);
x=yy,y=xx-a/b*yy;
return d;
}
解ax+by==c:
无解:
c%gcd(a,b)!=0
有解:
令d=gcd(a,b),原解为x’.
通解:x=x’*(c/d)+b/d,y=y’*(c/d)-a/d.
求x最小解:x=(x%b+b)%b.
中国剩余定理
用途:解同余方程组
已知有n个形如以下方式的式子:
XmodWi=Bi
X
m
o
d
W
i
=
B
i
(前提是所有的Wi必须两两互质)
设P为所有Wi的乘积,Mi为P/Wi
int China(int B[],int W[],int k){
int d,x,y,ans=0,Mi,P=1;
for(int i=1;i<=k;i++)P*=W[i];
for(int i=1;i<=k;i++){
Mi=P/W[i];
d=exgcd(Mi,W[i],x,y);
ans=(ans+x*Mi*B[i])%P;
}
if(ans>0)return ans;
return (ans+P);
}
求乘法逆元
以下方法前提都是模数为质数
方法一:求某一个数的乘法逆元,时间复杂度O(n)
//求a在mod b前提下的逆元
int Inverse(int a,int b){
int x,y;
if(exgcd(a,b,x,y)==1)return (x%b+b)%b;
return -1;//不存在逆元
}
方法二:线性筛,在O(n)时间复杂度内求出[1,n)内所有数的逆元
void Inverse(int n){
inv[1]=1;
for(int i=2;i<n;i++)inv[i]=(n-n/i)*inv[n%i]%n;
}
组合数
欧拉函数
用途:求phi(p)
时间复杂度:O(sqrt(p))
int phi(int p){
int ans=p,a=p;
for(int i=2;i*i<=a;i++)
if(a%i==0){
ans-=ans/i;
while(a%i==0)a/=i;
}
if(a>1)ans-=ans/a;
return ans;
}
欧拉筛
用途:求出[1,n]内所有数的phi(i)和这个范围内所有的质数
时间复杂度:O(n)
void getPhi(int n){
int cnt=0;
for(int i=2;i<=n;i++){
if(!mark[i])prime[++cnt]=i,phi[i]=i-1;
for(int j=1;j<=n && prime[j]*i<=n;j++){
mark[i*prime[j]]=true;
if(i%prime[j]==0){
phi[i*prime[j]]=phi[i]*prime[j];
break;
}else phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
}
Miller-Rabin素数测试
用途:判断一个数是否是质数;该算法是不确定算法,判断准确的概率为75%,但是判断10次左右就可以保证基本正确且正确率极高。
时间复杂度:log3n.
//#include<cstdlib>
bool Miiler_Rabin(int n){
if(n==2)return true;
if(n<2 || n%2==0)return false;
int a,x,y,d=n-1,R=0;
while(!(d&1))d>>=1,R++;//去掉因子2
for(int i=1;i<=10;i++){
a=rand()%(n-2)+2;
//随机产生[2,n-1]内的底数
//最好是[2,41]内的质数为底数,long long内基本不会错
x=mont(a,d,n);
//a^d%n
for(int j=1;j<=R;j++){
y=x*x%n;
if(y==1 && x!=1 && x!=n-1)return false;
//x^2%n==1而x!=1 && x!=n-1,显然不符合条件
x=y;
}
if(x!=1)return false;
}
return true;
}
快速乘
用途:用于long long范围内的乘法
注:尽量不要用,因为速度较慢
//计算(a*b)%c
ll quick_mul(ll a,ll b,ll c){
ll ans=0;
while(b){
if(b&1)ans=(ans+a)%c;
b>>=1,a=(a<<1)%c;
}
return ans;
}