excrt(拓展中国剩余定理)
Posted oierglh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了excrt(拓展中国剩余定理)相关的知识,希望对你有一定的参考价值。
对于一个同余方程
对于第一个和第二个式子
则有:
ans=a1?+k1?∗n1?
ans=a2?+k2?∗n2?
就有:
a1?+k1?∗n1?=a2?+k2?∗n2?
k1?∗n1?−k2?∗n2?=a2?−a1?
故我们设c=a2?−a1? 再变化一下形式就有:
k1?∗n1?+(−k2?)∗n2?=c
令 gcd=gcd(n1?,n2?)
这样我们就可以通过exgcd来求出一组解x1?,y1?
满足 x1?∗n1?+y2?∗n2?=gcd
故:x1?∗d/g∗n1?+y2?∗d/g∗n2?=g∗c/gcd
则: k1?=x1?∗c/gcd,k2?=y1?∗c/gcd
从而得到一组通解((k1+q)*n1+(k2-p)*n2=c)
k1?=k1+q=k1?+n2/gcd∗T
k2?=k2-p=k2?−n1/gcd∗T
要使所求得的解最小且为正整数则可以根据 k1? 的通解形式求得
mink1?=(k1?%(n2?/gcd)+n2?/gcd)%(n2?/gcd)
再带入ans=a1?+mink1?∗n1? 得到 ans
令 A 为合并后的 a , N 为合并后的 n
所以N=lcm(n1?,n2?)=n1?∗n2?/gcd
根据ans≡A (mod N) 且 ans 是满足该式子最小的值
得到: A=ans
代码
#include<bits/stdc++.h> using namespace std; #define ll __int128 ll ans,a[100010],n[100010],N,a1,a2,n1,n2,c,gcd,x,y; long long read() ll f=1,x=0; char ss=getchar(); while(ss<‘0‘||ss>‘9‘)if(ss==‘-‘)f=-1;ss=getchar(); while(ss>=‘0‘&&ss<=‘9‘)x=x*10+ss-‘0‘;ss=getchar(); return f*x; void exgcd(ll aa,ll bb,ll &gcd,ll &x,ll &y) if(!bb) gcd=aa; x=1,y=0; return; exgcd(bb,aa%bb,gcd,x,y); ll tr=x; x=y; y=tr-aa/bb*y; long long zs() a1=a[1],n1=n[1]; for(ll i=2;i<=N;i++) a2=a[i],n2=n[i]; c=a2-a1; exgcd(n1,n2,gcd,x,y);//n1*x+n2*y=gcd(n1,n2)的解 if(c%gcd==0) ll k1=x*c/gcd;//n1*k1+n2*k2=c的解 ll mink1=(k1%(n2/gcd)+(n2/gcd))%(n2/gcd);//k1通解:k1=k1+(n2/gcd)*t ans=mink1*n1+a1;//这2个方程的解 //合并2个方程 n1=(n1*n2)/gcd; a1=ans; else return -1; return ans; int main() N=read(); for(ll i=1;i<=N;i++) n[i]=read(),a[i]=read(); cout<<zs(); return 0;
部分参考来自https://www.luogu.org/blog/sumijie/solution-p4777。
以上是关于excrt(拓展中国剩余定理)的主要内容,如果未能解决你的问题,请参考以下文章
EXCRT模板POJ2891/LuoGu4777Strange Way to Express Integers拓展中国剩余定理
中国剩余定理(CRT) & 扩展中国剩余定理(ExCRT)总结