poj2891

时间:2022-05-23 03:49:19

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

首先我们回忆一下中国剩余定理对于给定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,但可以忽视……)

 #include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<stdlib.h>
#define ll long long
using namespace std;
int k;
ll a1,a2,p1,p2,x,y; ll gcd(ll a,ll b)
{
return (b==)?a:gcd(b,a%b);
}
void exgcd(ll a,ll b,ll &x,ll &y)
{
if (b==) {x=; y=; return;}
exgcd(b,a%b,x,y);
ll xx=x,yy=y;
x=yy; y=xx-(a/b)*yy;
} int main()
{
while (scanf("%d",&k)!=EOF)
{
scanf("%lld%lld",&p1,&a1);
a1%=p1;
bool ch=;
for (int i=; i<=k; i++)
{
scanf("%lld%lld",&p2,&a2);
if (ch) continue;
a2%=p2;
ll g=gcd(p1,p2);
if ((a1-a2)%g)
{
ch=;
continue;
}
ll a=p1/g,c=(a1-a2)/g;
exgcd(a,p2/g,x,y); y=(y+a)%a;
y=(y*c%a+a)%a;
p1=p1*(p2/g); a1=(a2+p2*y%p1)%p1;
}
if (ch) puts("-1");
else printf("%lld\n",a1);
}
system("pause");
return ;
}