数论总结
线性筛 求范围内质数
void Prime(int n)
{
int i,j;
for (i=2;i<=n;i++)
{
if (!not_prime[i]) prime[++cnt]=i;
for (j=1;j<=cnt && i*prime[j]<=n;j++)
{
not_prime[i*prime[j]]=1;
if (i%prime[j]==0) break;//保证每个数都是被最小质因子筛掉的
}
}
}
快速幂 log(b)复杂度求解ab
int pow(int a,int k,int mod)
{
int ans=1;
while (k)
{
if (k&1) ans=1ll*ans*a%mod;
a=1ll*a*a%mod;
k>>=1;
}
return ans;
}
矩阵快速幂 用结构体存矩阵会方便一点
struct Mat
{
int m[maxn][maxn];
}ans,a;
Mat mul(Mat a,Mat b,int n)
{
int i,j,k;
Mat c;
memset(c.m,0,sizeof(c.m));
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
for(k=1;k<=n;k++)
c.m[i][j]=(c.m[i][j]+1ll*a.m[i][k]*b.m[k][j]%mod)%mod;
return c;
}
void Pow(Mat a,int k,int n)
{
memset(ans.m,0,sizeof(ans.m));
for(int i=1;i<=n;i++) ans.m[i][i]=1;
while (k)
{
if (k&1) mul(ans,a,n);
mul(a,a,n);
k>>=1;
}
}
欧几里得求最大公因数 gcd(m, n) = gcd(n, m mod n)
int gcd(int a,int b)
{
if (b==0) return a;
return gcd(b,a%b);
}
Theorem (裴蜀定理)
若 a 和 b 是整数,方程 ax+by=d 有整数解当且仅当 gcd(a, b) | d,即d是gcd(a,b)的倍数。
扩展欧几里得算法求解ax+by=gcd(a,b) 求出该方程的解x0,y0后,可知通解为x=x0+(b/gcd)*t y=y0-(a/gcd)*t
#include<cstdio>
int exgcd(int a,int b,int& x,int& y)
{
if (b==0)
{
x=1;y=0;
return a;
}
int g=exgcd(b,a%b,x,y);
int t=x;
x=y;
y=t-a/b*y;
return g;
}
int main()
{
int a,b,x,y;
scanf("%d%d",&a,&b);
exgcd(a,b,x,y);
printf("%d %d\n",x,y);
return 0;
}
同余的性质
如果 a1 ≡ b1(mod m) , a2 ≡ b2(mod m)
那么 a1±a2 ≡ b1±b2(mod m) , a1a2 ≡ b1b2(mod m)
逆元
对于(b/a)%p操作,我们只要找到一个x,0<=x<=p-1,使得ax ≡ 1(mod p),就可以用bx%p来表示(b/a)%p的值
我们将其中的x称为a的逆元,记作inv(a)
求逆元的方法
1、扩展欧几里得
ax ≡ 1(mod p)可以化为ax+tp=1,已知a,p即可求解x,t
2、快速幂
根据欧拉定理(费马小定理)有ap-1 ≡ 1(mod p) 即ap-2a ≡ 1(mod p)
所以inv(a)=ap-2%p
威尔逊定理
(p-2)! ≡ 1(mod p) (p为质数)