poj2891
中国剩余定理考虑模数不互质的情况
太懒了> - <
解同于方程组:
x≡r1(moda1)x≡r2(moda2)......x≡rn(modan)x≡r1(moda1)x≡r2(moda2)......x≡rn(modan)
其中模数不一定互质。
题解
若模数两两互质,我们可以用中国剩余定理来解。
这里我们先考虑两个方程:
x≡r1(moda1)x≡r2(moda2)x≡r1(moda1)x≡r2(moda2)
我们可以写成:
x+y1a1=r1x−y2a2=r2x+y1a1=r1x−y2a2=r2
相减得:y1a1+y2a2=r1−r2y1a1+y2a2=r1−r2也就是ax+by=max+by=m的形式。
这是可以用扩展欧几里德解的。
若gcd(a,b)/|mgcd(a,b)⧸|m那么方程就无解,直接输出-1。
否则我们可以解出上式的y1y1。回带得到一个特解x0=r1−y1a1x0=r1−y1a1。
通解可以写成x=x0+k∗lcm(a1,a2)x=x0+k∗lcm(a1,a2)也就是x≡x0(modlcm(a1,a2))x≡x0(modlcm(a1,a2))。
这样我们就将两个方程合并为了一个。重复进行以上操作,我们最终能将n个方程全部合并,再用扩展欧几德得解出来就好了。
ll solve(){
ll M=a[1],R=r[1],x,y,d;
for(int i=2;i<=n;i++){
d=exgcd(M,a[i],x,y);
if((R-r[i])%d!=0) return -1; //无解
x=(R-r[i])/d*x%a[i]; //这才是真正的x,记得模a[i]。
R-=x*M; //特解x0,新的余数。
M=M/d*a[i]; //新的模数。
R%=M;
}
return (R%M+M)%M;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
下面是完整代码:
#include<cstdio> #include<cctype> #define ll long long using namespace std; ll a[100005],r[100005]; int k; inline void read(ll &x){ char ch=getchar();x=0; while(!isdigit(ch))ch=getchar(); while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} } ll exgcd(ll a,ll b,ll &x,ll &y){ if(!b){x=1;y=0;return a;} else{ll tmp=exgcd(b,a%b,y,x);y-=(a/b)*x;return tmp;} } ll solve(){ ll M=a[1],R=r[1],x,y,d; for(int i=2;i<=k;i++){ d=exgcd(M,a[i],x,y); if((R-r[i])%d!=0)return -1; x=(R-r[i])/d*x%a[i]; R-=x*M; M=M/d*a[i]; R%=M; } return (R%M+M)%M; } int main(){ while(~scanf("%d",&k)){ for(int i=1;i<=k;i++){read(a[i]);read(r[i]);} printf("%lld\n",solve()); } }