1.欧几里得算法(gcd)
int gcd(int a,int b)
{return b == 0 ?a:gcd(b,a%b);}
输入两个数返回这两个数的gcd
2.扩展欧几里得算法(exgcd)
void exgcd(int a,int b,int &x,int &y)
{
int t;
if(b = = 0){x=1;y=0;return;}
exgcd(b,a%b,x,y);
t=x;x=y;y=t-a/b*y;
}
输入两个数和两个0,计算ax+by=gcd(a,b)的一组解
ps:同余方程的等价操作 ax同余1 modb < = = >ax+by=1
3.快速幂
int quickpow(int a,int b,int c)
{
int ans=1;a=a%c;
while(b>0)
{if(b%2==1)ans=(ans*a)%c;
b=b/2;a=a*a%c;}return ans;
}
输
入三个数a,b,c,返回a^b%c
4.快速乘(o(1))
inline long long multi(long long x,long long y,long long mod)
{
long long tmp=(x*y-(long long)((long double)x/mod*y+1.0e-8)*mod);
return tmp<0 ? tmp+mod : tmp;
}
输入两个数和模数,返回两个数乘积模mod数(防爆long long)
5.线性素数筛
void pri(int x)
{
cnt = 0;
used[0]=used[1]=1;
int i,j;
for(i=2;i<=x;i++)
{
if(!used[i])
p[cnt++] = i;
for(j=0;j<cnt&&i*p[j]<x;j++)
{
used[i*p[j]]=1;
if(i%p[j]==0)
break;
}
}
}
输入一个x,把小于x的质数都放在p数组内
6.欧拉函数
void oula(int n)
{
int i,j;
for(i=1;i<=n;i++)
phi[i]=i;
for(i=2;i<=n;i+=2)
phi[i]/=2;
for(i=3;i<=n;i+=2)
{
if(phi[i]==i)
{
for(j=i;j<=n;j+=i)
phi[j]=phi[j]/i*(i-1);
}
}
}
将前n个数的欧拉函数值存在phi数组内
ps:欧拉函数(与该数互质数的个数)
7.exgcd求逆元
逆元就是ax与1同余mod m下,a与m互质时有唯一解,那么转化一下,就是ax+mody=gcd(a,mod)而且a和mod互质时有解,那么就转化成了ax+mody=1在使用扩展欧几里得算法计算就可以得到逆元了。
int inv(int a)
{
int x,y;
x=0,y=0;
exgcd(a,mod,x,y);
return (x%mod+mod)%mod;
}
8.逆元打表
逆元还有一种线性的递推求法,可以on的复杂度求出n以内的乘法逆元
inv[1]=1LL;
for(i=2;i<=n;i++)
inv[i]=(long long)mod-mod/i*inv[mod%i]%mod;
9.中国剩余定理
求一个方程组x同余ai(mod mi)的解x
其中m1,m2,m3…两两互质
int crt(int a[],int m[],int n)
{
int M=1,i,j;
for(i=1;i<=n;i++)M*=m[i];
int ret=0;
for(i=1;i<=n;i++)
{
int x,y;
int tm=M/m[i];
exgcd(tm,m[i],x,y);
ret=(ret+tm*x*a[i])%M;
}
return (ret+M)%M;
}