POJ2891:Strange Way to Express Integers——题解

http://poj.org/problem?id=2891

题目大意:

k个不同的正整数a1,a2,...,ak。对于一些非负m,满足除以每个ai(1≤i≤k)得到余数ri。求出最小的m。

输入和输出中的所有整数都是非负数,可以用64位整数类型表示。

——————————————

首先我们打眼一看可能是孙子定理。

但是我们无法保证a一定互质。

那么显然就要用我们的可爱的exgcd啦!

(下面题解根据这位大佬所懂http://blog.csdn.net/zmh964685331/article/details/50527894)

显然对于x=r(mod a)

我们有:

x+y1a1=r1①

x-y2a2=r2②

x-y3a3=r3③

……

①②相减得:

y1a1+y2a2=r1-r2

我们就有了标准的exgcd的方程了。

不能解就是-1

否则我们能求出其中一个y1,将其化为最小值后,带入①得到

x0=r1-y1a1

这是x的其中一个解,全解为

x=x0+k*lcm(a1,a2)

x=x0(mod lcm(a1,a2))

则:

x+y3*lcm(a1,a2)=x0④

③④再联立,重复以上过程即可。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cctype>
using namespace std;
typedef long long ll;
inline ll read(){
    ll X=0,w=0; char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
ll exgcd(ll a,ll b,ll &x,ll &y){
    if(b==0){
    x=1;y=0;
    return a;
    }
    ll r=exgcd(b,a%b,x,y);
    ll temp;
    temp=x;
    x=y;
    y=temp-(a/b)*y;
    return r;
}
ll a[100001],r[100001];
int main(){
    int k;
    while(scanf("%d",&k)!=EOF){
    bool ok=0;
    for(int i=1;i<=k;i++){
        a[i]=read();
        r[i]=read();
    }
    ll a1=a[1],r1=r[1];
    for(int i=2;i<=k;i++){
        ll A=a1,B=a[i],C=r1-r[i];
        ll x,y;
        ll g=exgcd(A,B,x,y);
        if(C%g){
        printf("-1\n");
        ok=1;
        break;
        }
        x=C/g*x%a[i];
        r1=r1-x*a1;
        a1=a1*a[i]/g;
    }
    if(ok)continue;
    printf("%lld\n",(r1%a1+a1)%a1);
    }
    return 0;
}
posted @ 2017-11-27 19:34  luyouqi233  阅读(130)  评论(0编辑  收藏  举报