• POJ2891 Strange Way to Express Integers


    传送门

    题目大意:求解同余方程组,不保证模数两两互质。

    如果模数互质的话,那么我们可以用CRT求解,要是不互质呢?我们就没办法了吗?当然不是。我们可以用exgcd将方程合并来求解。

    首先我们先以两个方程为例:

    A ≡ r1 (mod a1)

    A ≡ r2 (mod a2)

    我们把这两个方程写成这样的形式:A = r1 - x * a1,A = r2 + y * a2.

    两式相减一下,得到:x * a1 + y * a2 = r1 -  r2.

    这就是一个不定方程的形式。它有解的条件是 (a1,a2) | r1 - r2,否则这个方程无解,那么整个同余方程组也无解。

    如果有解的话,那么我们可以先用exgcd求出不定方程的特解x,把它乘以(r1-r2)/(a1,a2),这样的话我们就得到了最小正整数解x,把它带回到第一个同余方程里,那么我们就知道了一个A的特解A0。

    之后,又因为A的解必然与A0关于[a1,a2]同余(这个是定理),那么我们就得到了一个新的同余方程:A≡A0 (mod [a1,a2])

    我们就把两个方程合并为一个方程,之后继续合并即可得解,注意合并过程中任意一次出现无解的情况那么整个方程即无解。

    看一下代码。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<queue>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    
    using namespace std;
    typedef long long ll;
    const int M = 1000005;
    
    int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-') op = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            ans *= 10;
            ans += ch - '0';
            ch = getchar();
        }
        return ans * op;
    }
    
    ll n,r[M],a[M],x,y;
    
    ll exgcd(ll a,ll b,ll &x,ll &y)
    {
        if(!b) 
        {
            x = 1,y = 0;
            return a;
        }
        ll d = exgcd(b,a%b,y,x);
        y -= a / b * x;
        return d;
    }
    
    ll solve()
    {
        ll M = a[1],R = r[1];
        rep(i,2,n)
        {
            ll d = exgcd(M,a[i],x,y);
            if((R - r[i]) % d) return -1;
            x = (R - r[i]) / d * x % a[i];//x是本次解得的一组特解
            R -= x * M;//R是现在的余数,也就是A0
            M = M / d * a[i];//M是新的模数,也就是[a1,a2] 
            R %= M;
        }
        R = (R+M) % M;
        return R;
    }
    
    int main()
    {
        while(scanf("%lld",&n) != EOF)
        {
            rep(i,1,n) a[i] = read(),r[i] = read();
            printf("%lld
    ",solve());
        }
        return 0;
    }
  • 相关阅读:
    JavaScript文件加载器LABjs API详解 转
    AMD及requireJS 转
    C#中数组、ArrayList和List三者的区别 转
    CSS魔法堂:那个被我们忽略的outline
    CSS魔法堂:改变单选框颜色就这么吹毛求疵!
    CSS魔法堂:display:none与visibility:hidden的恩怨情仇
    CSS魔法堂:一起玩透伪元素和Content属性
    CSS魔法堂:稍稍深入伪类选择器
    CSS魔法堂:更丰富的前端动效by CSS Animation
    CSS魔法堂:Transition就这么好玩
  • 原文地址:https://www.cnblogs.com/captain1/p/9783918.html
Copyright © 2020-2023  润新知