1.求乘法逆元
扩展欧几里得算法
欧几里得算法:任意a,b∈N,b≠0,gcd(a,b) = gcd(b,a mod b)
定理1: 设a和b不全为0,则存在整数x和y,使得ax + by = gcd(a,b)。
当b = 0时,ax + by = gcd(a,b) 有一组解为x = 1,y = 0。
当b ≠ 0时,bx' + (a%b)y' = gcd(b,a%b) = gcd(a,b)
bx' + (a - a / b × b)y' = gcd(a,b) (此时 / 为整除)
ay' + b(x' - (a / b) y') = gcd(a,b)
令x = y',y = x' - (a / b)y',则ax + by = gcd(a,b)
void exgcd(int a,int b,long long &x,long long &y){ if(!b)x = 1,y = 0; else exgcd(b,a%b,y,x),y -= a/b*x; }
exgcd(i,p,x,y);
(x % b + b) % b // 求最小正整数解
还有线性算法的,给个大佬博客:传送门
2.中国剩余定理
void exgcd(int a,int b,int &x,int &y) { if(b==0){ x=1; y=0; return;} exgcd(b,a%b,x,y); int tp=x; x=y; y=tp-a/b*y; } int china() { int ans=0,lcm=1,x,y; for(int i=1;i<=k;++i) lcm*=b[i]; for(int i=1;i<=k;++i) { int tp=lcm/b[i]; exgcd(tp,b[i],x,y); x=(x%b[i]+b[i])%b[i];//x要为最小非负整数解 ans=(ans+tp*x*a[i])%lcm; } return (ans+lcm)%lcm; }
eg 1:
Biorhythms POJ - 1006
while(~scanf("%d%d%d%d",&p,&e,&i,&d)) { if(d == -1)break; x=(5544*p+14421*e+1288*i-d+21252)%21252; if(x==0) x=21252; printf("Case %d: the next triple peak occurs in %d days. ", ++icase, x); }
3.扩展欧几里得算法
lt exgcd(lt a,lt b,lt &x,lt &y) { if(b==0){x=1;y=0;return a;} lt gcd=exgcd(b,a%b,x,y); lt tp=x; x=y; y=tp-a/b*y; return gcd; } lt excrt() { lt x,y,k; lt M=bi[1],ans=ai[1]; for(int i=2;i<=n;i++) { lt a=M,b=bi[i],c=(ai[i]-ans%b+b)%b; lt gcd=exgcd(a,b,x,y),bg=b/gcd; if(c%gcd!=0) return -1; x=mul(x,c/gcd,bg); ans+=x*M; M*=bg; ans=(ans%M+M)%M; } return (ans%M+M)%M; }