POJ 2891 扩展欧几里德

这个题乍一看跟剩余定理似的,但是它不满足两两互素的条件,所以不能用剩余定理,也是给了一组同余方程,找出一个X满足这些方程,如果找不到的话就输出-1

因为它不满足互素的条件,所以两个两个的合并,最后合成一个。

题目给定的是

M % m1 = r1

M % m2 = r2

......

M % mn = rn

只需将两个式子合并成一个式子,那么这个合并的这个式子就可以继续和下面的式子继续合并,知道合到最后一个式子。

首先来看下两个式子怎么合并。

M % m1 = r1    可以写成  M = k1 * m1 + r1;

同理M =  k2 * m2 + r2

所以k1 * m1 + r1  = k2 * m2 + r2

k1 * m1 - k2 * m2 = r2 - r1

将k1 看成x, m1看成a, k2看成y, m2看成b, r2 - r1看成c

那么这个式子就变成了

ax-by=c;不定方程

这时候就可以用不定方程来解了。

因为题目给的两两可能不互素,所以gcd(a, b) 有可能不等于1,所以,这个方程不一定有解,所以就是判断这个题有没有解的条件。

如果有解的话,用扩展欧几里德可以的出这个方程的解,然后将x带入到 k1 * m1 + r1中得到M,这时候M就是这两个方程组的一个特解,通解就是M' = M + K * LCM(m1, m2);

这个式子可以变化成M' % LCM(m1, m2) = M;所以又可以继续跟下面的式子合并了。所以这个式子对应的余数r就是M, 模数(就是式子中的mi)就是LCM(m1,m2);

到这里之后就合并好了一个式子。下面就是继续按照这个过程合并到第n个式子了。最后合并完之后就剩下一个式子,求出来的M就是方程组的特解,通解为M' = M + k * LCM; 其中LCM = LCM(m1, m2...mn), 最小正整数解为(M %  LCM + LCM) % LCM;

还有一个坑就是如果边输入边处理的话,不要找到无解立马就跳出循环,因为后面的数据还没输入完。

代码如下:

    /*************************************************************************
        > File Name: 5.cpp
        > Author: Howe Young
        > Mail: 1013410795@qq.com 
        > Created Time: 2015年08月01日 星期六 15时39分47秒
     ************************************************************************/

    #include <iostream>
    #include <cstdio>
    using namespace std;
    const int maxn = 1e5 + 5;
    typedef long long ll;
    ll m[maxn], r[maxn];
    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 t = x;
        x = y;
        y = t - a / b * y;
        return r;
    }
    int main()
    {
        int k;
        while (~scanf("%d", &k))
        {
            for (int i = 1; i <= k; i++)
                scanf("%lld %lld", &m[i], &r[i]);
            ll m1, m2, r1, r2, c, d;
            m1 = m[1]; r1 = r[1];
            bool flag = true;
            for (int i = 2; i <= k; i++)
            {
                ll x, y;
                d = exgcd(m1, m[i], x, y);
                if ((r[i] - r1) % d != 0)
                {
                    flag = false;
                    break;
                }
                c = r[i] - r1;
                x = c / d * x % (m[i] / d);
                r1 = m1 * x + r1;
                m1 = m1 / d * m[i];
                r1 %= m1;
            }
            if (!flag)
            {
                printf("-1\n");
                continue;
            }
            r1 = (r1 + m1) % m1;
            printf("%lld\n", r1);
        }

        return 0;
    }
View Code

 

posted @ 2015-08-01 17:21  Howe_Young  阅读(349)  评论(0编辑  收藏  举报