1. 程式人生 > >中國剩餘定理(互質+非互質)

中國剩餘定理(互質+非互質)

給定n組同餘方程,求x。
xa1(mod m1)
xa2(mod m2)
xa3(mod m3)
……
xan(mod mn)

  • mi兩兩互素,則x必定有解。

    M=m1m2...mn
    x=(a1M1M1+a2M2M2+...+anMnMn)mod M

    其中Mi=M/mi
    MiMimodmi的逆。

#include <iostream>
#include <algorithm>
using namespace std;

typedef long long LL;

int n;
int a[15], m[15];

void
ex_gcd(int a, int b, int &x, int &y) { if(!b) { x = 1; y = 0; } else { ex_gcd(b, a%b, y, x); y -= (a / b) * x; } } LL CRT(int a[], int m[]) { LL M = 1; LL ans = 0; for(int i = 0; i < n; i++) M *= m[i]; for(int i = 0
; i < n; i++) { LL t = M / m[i]; int x, y; ex_gcd(t, m[i], x, y); ans += a[i] * t * x; ans %= M; } ans = (ans + M) % M; return ans; } int main(int argc, char const *argv[]) { cin >> n; for(int i = 0; i < n; i++) cin >> m[i] >> a[i]; cout
<< CRT(a, m); return 0; }
  • mi非互質

    對前兩個方程
    xa1(mod m1)
    xa2(mod m2)

    m1y1m2y2=a2a1

    解出最小y1,x=a1+m1y1
    兩個方程可以合成為yx(mod lcm(m1,m2))
    一隻合併下去,就可以得到最終結果。
    若方程無解,無法合併,則最終無解。

    對於題目所給正整數的要求,只有一種反例,就是結果輸出為0的情況,
    這個可以特殊考慮,只需要考慮所有數的最小公倍數即可。

//hdu 5668 circle
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

int c[25], vis[25], a[25], m[25];

void ex_gcd(int a, int b, int &d, int &x, int &y)
{
    if(!b)
    {
        d = a;
        x = 1;
        y = 0;
    }
    else
    {
        ex_gcd(b, a%b, d, y, x);
        y -= (a / b) * x;
    }
}
int CRT(int n)
{
    int c = a[1], l = m[1];
    int d, x, y;
    for(int i = 2; i <= n; i++)
    {
        ex_gcd(l, m[i], d, x, y);
        if((a[i]-c)%d)
            return -1;
        int tt = m[i] / d;
        x = (a[i] - c) / d * x % (m[i] / d);
        c += l * x;
        l = l / d * m[i];
        c %= l;
    }
     return (c + l) % l ? (c + l) % l : l;  
}
int main(int argc, char const *argv[])
{
    int t;
    cin >> t;
    while(t--)
    {
        int tmp, n;
        cin >> n;
        for(int i = 1; i <= n; i++)
        {
            cin >> tmp;
            c[tmp] = i;
        }
        memset(vis, 0, sizeof(vis));
        int j = 0;
        for(int i = 1; i <= n; i++)
        {
            int k = 0;
            while(j != c[i])
            {
                j++;
                if(j > n)
                    j = 1;
                if(!vis[j])
                    k++;
            }
            vis[c[i]] = 1;
            a[i] = k;
            m[i] = n - i + 1;
            a[i] %= m[i];
        }

        int ans = CRT(n);
        if(ans != -1)
            printf("%d\n", ans);
        else
            printf("Creation August is a SB!\n");
    }
    return 0;
}