1.gcd&exgcd
1.gcd: 辗转相除。
int gcd(int x,int y){
if(y==0) return x;
return gcd(y,x%y);
}
2.exgcd:
裴蜀定理:对于任意正整数a,b,一定存在非零数对(x,y),满足ax+by=gcd(a,b).
(gcd(a,b)=gcd(b,a\%b))
设(x',y')是方程$ by'+ (a % b) x' =gcd(b,a%b) $的解
$ by'+ (a % b) x' =gcd(a,b) $
$ by'+ (a-b(a/b)) x' =gcd(a,b) $
$ ax'+by'-b(a/b)x' =gcd(a,b) $
$ ax'+b(y'-(a/b)x') =gcd(a,b) $
(x=x',y=y'-(a/b)x')
int exgcd(int a,int b,int &x,int &y){
if(b==0) {x=1;y=0;return a;}
int d=exgcd(b,a%b,y,x);y-=a/b*x;
return d;
}
2.欧拉函数
(phi(n)) 表示小于等于 (n) 且与 (n) 互质的数的个数。
(phi(n)=nprod_{p|n} (1-frac 1 p))
特别地,(phi(1)=1).
感性理解一下。证明不会
1.(O(sqrt n)) 筛质因数求欧拉函数。
@[墨染空] 的代码
int phi = x;
for(int j = 2; j * j <= x; j++){
if(x % j == 0){
phi = phi / j * (j - 1);
while(x % j == 0) x /= j;
}
}
if(x > 1) phi = phi / x * (x - 1);
2.(O(n)) 线性筛出(1-n)的(phi (i))
由定义可知,(phi (p) =p-1)
如果(p|x,phi (px)=p phi(x))
否则,(phi (px)=(p-1) phi(x))
证明不会
这份是我的代码
phi[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i]) p[++cnt]=i,phi[i]=i-1;
for(int j=1;j<=cnt&&i*p[j]<=n;j++){
vis[i*p[j]]=1;
if(i%p[j]==0){
phi[i*p[j]]=phi[i]*p[j];
break;
}
phi[i*p[j]]=phi[i]*(p[j]-1);
}
}
3.逆元
两种。
1.费马小定理(p为质数)
(a^{p-1} equiv 1 mod p)
(a^{p-2} equiv frac 1 p mod p)
(inv(x)=x^{p-2} mod p)
快速幂。
2.exgcd
(xinv(x) equiv 1 mod p)
设(s=inv(x))
(xs equiv 1 mod p)
(xs+pt=1)
exgcd。
4.crt&excrt
crt不会 反正excrt挺好的。
模板题
现在有n个形如$ x equiv a_i pmod {b_i}$的方程
假设前k-1个方程的最小正整数解是(ans_{k-1},)
令(M=gcd(b_1,b_2,……,b_{k-1}))
设(ans_k=ans_{k-1}+xM(x为整数))
则(ans_{k-1}+xM equiv a_k pmod {b_k})
(∴Mxequiv {{a_k}-{ans_{k-1}}} pmod {b_k})
(Mx+{b_k}y={{a_k}-{ans_{k-1}}})
exgcd。
题目的a,b读入是反的,注意。 还有记得开longlong。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int n;
LL ans,M=1;
LL gcd(LL x,LL y){ return y?gcd(y,x%y):x; }
LL lcm(LL x,LL y){ return x*y/gcd(x,y); }
LL exgcd(LL A,LL B,LL &x,LL &y){
if(!B){ x=1,y=0;return x; }
else{
LL d=exgcd(B,A%B,y,x);
y-=A/B*x;return d;
}
}
void crt(LL A,LL B){
LL a=M,b=B,c=((A-ans)%B+B)%B,x,y;
LL g=exgcd(a,b,x,y);
if(c%g) return;
x=((x*(c/g))%B+B)%B;ans+=x*M;
M=lcm(M,B);ans=(ans%M+M)%M;
}
int main(){
scanf("%d",&n);
LL a,b;
for(int i=1;i<=n;i++)
scanf("%lld%lld",&a,&b),crt(b,a);
printf("%lld
",ans);
return 0;
}