数论(初级)
目录
- GCD、LCM
- 扩展GCD
- 素数
- 快速幂
- 快速乘法取模
- 逆元
- 费马小定理&&欧拉定理
- 线性递推求逆元
- 欧拉函数
1.GCD、LCM
//GCD(最大公约数)模板
void GCD(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
//LCM(最小公倍数)模板
void LCM(int a,int b)
{
return a/GCD(a,b)*b;
}
2.拓展GCD
其作用为求解方程:ax+by=c
首先c的最小值只能为gcd(a,b)。
证明:令ax+by可以得到的最小取值为s,显然gcd(a,b)|ax+by,那么gcd(a,b)|s。令q=a/s (小数部分舍去),r=amods=a-q*s=a-q*(ax+by)=a(1-qx)+b(-qy) 显然 r也是线性组合,由于s是最小取值,那么r=0 所以s|a,同理s|b,所以s|gcd(a,b) 所以s=gcd(a,b)
注意:设其中的一组解为(x0,y0),这它的任意整数解都可以写成(x0+kb’,y0-ka’),其中a’ = a/gcd(a,b) , b’ = b/gcd(a,b),要求最小正数解的话可以采取取模再取模的方法(不明确写出)
//exGCD模板
int exGcd(int a,int b,int& x,int &y)
{
if(b==0){
x = 1;
y = 0;
return a;
}
int r = exGcd(b,a%b,x,y);
int t = x;
x = y;
y = t-a/b*y;
return r;
}
3.素数
正常判定时的复杂度为O(sqrt(n))
1.素数筛法(O(nlogn))
int m = sqrt(n + 0.5)
memset(vis, 0, sizeof(vis));
for(int i = 2; i<=m; i++)
if(!vis[i])
for(int j = i*i; j<=n; j = j+i)
vis[j] = 1;
4.快速幂
其算法实现的大概方法就是将十进制转化为二进制11的二进制(1011,11 = 2³×1 + 2²×0 + 2¹×1 + 2º×1)
long long qpow(long long a,long long b,long long p)
{
long long ans = 1;
while(b)
{
if(b&1) ans = ans * a %p;
b>>=1;
a = a*a%p;
}
return res;
}
5.快速乘法取模
long long qmult(long long a,long long b,long long p)
{
long long res = 0;
while(b)
{
if(b&1) res = (res+a)*p;
b>>=1;
a = (a+a)%p;
}
return res;
}
6.逆元
数论倒数
指的是a*x = 1(mod p)的解
其意义在于在计算中用乘法代替除法避免一些函数无法算除法的缺陷。
**求法:**ax=1(mod p) = ax + kp =1因为只有在a,p互质的情况下才会出现逆元,所以这个方程有解(通过扩展GCD求逆元)。
7.费马小定理&&欧拉定理
费马小定理:对于质数p如果gcd(a,p) = 1,那么a^(p-1)=1(mod p)。显然,a^(p-2)*a=1(mod p),可以看出a^(p-2)为a的逆元
。
欧拉定理:f(x)为[1,x-1]内互质的个数a^(f(p))=1(mod p)
8.线性递推求逆元
这个方法可以求得1~x内对p的逆元,且p是个质数。
方法:首先1的逆元肯定是1。对于i,可以让p = ki+r(r
9.线性递推求逆元
前面讲过欧拉定理 那么如何来求这个f(x) 呢?
令x=p1^a1*p2^a2*p3^a3….pn^an
那么f(x)=x*(p1-1)/p*(p2-1)/p….(pn-1)/p
显然 f(p)=p-1 如果p为质数
//j计算单个欧拉函数
long long phi(long long n)
{
long long res = n;
for(long long i = 2;i*i<=n;i++)
{
if(n%i==0)
{
res/=(i);
res*=(i-1);
while(n%i==0) n/=i;
}
}
if(n>1)
{
res/=n;
res*=(n-1);
}
return res;
}
差不多简单数论的知识就是这么多