poj2891

这道题就是扩展的中国剩余定理(模数不互质)

首先我们回忆一下中国剩余定理对于给定n个方程组x≡ai(mod pi)

令m=∏pi wi=m/pi,然后求解关于hi,ri的方程wi*hi+pi*ri=1

令ei=wi*hi,则x≡∑eiai (mod m) 简单的验证一下,拿每个pi去模x,

因为除了wi意外,其他wj都是pi的倍数,很容易发现是复合条件的

但是当pi不互质时,上述就失效了,所以我们不能再用中国剩余定理

我们就觉得办法是用增量法,假设现在已经得到满足前k个同余方程的最小解ans

对于下一个方程x≡a(mod p),

我们不难想到满足单一同余方程的解x=a+p*k,满足前k个同余方程的解x=ans+lcm(pi)*k

现在我们只要令a+p*k=ans+lcm(pi)*k',找到这个二元一次方程的解

就能找到满足前k+1个同余方程的最小解,显然这是用扩展欧几里得解决

注意这道题说输入和输出可以用int64表示,但很容易中间量爆int64,理论用高精度

实际全部用long long好像就能过了(注意discuss中部分数据会造成中间量爆int64,但可以忽视……)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<stdlib.h>
 6 #define ll long long
 7 using namespace std;
 8 int k;
 9 ll a1,a2,p1,p2,x,y;
10 
11 ll gcd(ll a,ll b)
12 {
13    return (b==0)?a:gcd(b,a%b);
14 }
15 void exgcd(ll a,ll b,ll &x,ll &y)
16 {
17      if (b==0) {x=1; y=0; return;}
18      exgcd(b,a%b,x,y);
19      ll xx=x,yy=y;
20      x=yy; y=xx-(a/b)*yy;
21 }
22 
23 int main()
24 {
25     while (scanf("%d",&k)!=EOF)
26     {
27           scanf("%lld%lld",&p1,&a1);
28           a1%=p1;
29           bool ch=0;
30           for (int i=2; i<=k; i++)
31           {
32               scanf("%lld%lld",&p2,&a2);
33               if (ch) continue;
34               a2%=p2;
35               ll g=gcd(p1,p2);
36               if ((a1-a2)%g)
37               {
38                  ch=1;
39                  continue;
40               }
41               ll a=p1/g,c=(a1-a2)/g; 
42               exgcd(a,p2/g,x,y); y=(y+a)%a;
43               y=(y*c%a+a)%a;
44               p1=p1*(p2/g); a1=(a2+p2*y%p1)%p1;
45           }
46           if (ch) puts("-1");
47           else printf("%lld
",a1);
48     }          
49     system("pause");
50     return 0;
51 }
View Code
原文地址:https://www.cnblogs.com/phile/p/5646481.html