CF 338 D GCD Table(CRT)

acm_cxlove發表於2013-08-18

轉載請註明出處,謝謝http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove

給定一個序列,a[1 。。k],問是否存在(i , j)使得 GCD(i , j + r - 1) = a[r]  (k>=r >=1),其中 i <= n && j + k - 1 <= m

http://codeforces.com/contest/338/problem/D

首先容易知道row = lcm (a[1……k]),是最小可能存在解的行。

官方題解中有證明,反正亂七八糟的。。。我太弱了,看不懂

之後我們找到最小的col滿足

col % a[1] = 0

(col + 1) % a[2] = 0

……

(col + k - 1) % a[k] = 0

這個東西用CRT求出來。

最後check一下row , col是否滿足,就結束了。。。

顯然j < col 是不可能滿足的,而且col + x * row肯定也是可能滿足的。

當然可能存在gcd (col + r - 1 , row) > a[r]。

所以col縮小是肯定不滿足的,而即使你增大col若干倍,只可能使得偏差更大。

接下來就注意一下各種細節,比如溢位等問題

#include <iostream>
#include <queue>
#include <algorithm>
#include <cstdio>
#include <cstring>
#define lson step << 1
#define rson step << 1 | 1
using namespace std;
typedef long long LL;
const int N = 10005;
LL n , m , a[N] , row = 1LL;
int k;
LL gcd (LL a , LL b) {
    return b == 0 ? a : gcd (b , a % b);
}
LL extend_gcd (LL a , LL b , LL &x , LL &y) {
    if (b == 0) {
        x = 1LL;
        y = 0;
        return a;
    }
    LL g = extend_gcd (b , a % b , x , y);
    LL t = x;
    x = y; y = t - a / b * x;
    return g;
} 
int main() {
    int t;
    #ifndef ONLINE_JUDGE
        freopen ("input.txt" , "r" , stdin);
        // freopen ("output.txt" , "w" , stdout);
    #endif
    cin >> n >> m >> k;
    for (int i = 0 ; i < k ; i ++) {
        cin >> a[i];
        row = row / gcd (row , a[i]) * a[i];
        if (row <= 0 || row > n) {
            puts ("NO");
            return 0;
        }
    }
    // Z = u + v * x
    LL u = 0LL , v = a[0];
    for (int i = 1 ; i < k ; i ++) {
        // Z = U + V * x1
        // Z = - i + a[i] * x2
        // v * x - a[i] * y = - u - i
        // A * x + B * y = C
        LL x , y , A = v , B = -a[i] , C = - u - i;
        LL g = extend_gcd (A , B , x , y);
        if (C % g) {
            puts ("NO");
            return 0;
        }
        if (B % g) puts ("ERROR");
        LL t = B / g;
        x = x * (C / g);
        x = (x % t + t) % t;
        if (x < 0) x -= t;
        // y = (C - A * x) / B;
        u = u + v * x;
        v = v / gcd (v , a[i]) * a[i];
    }
    if (u == 0) u += row;
    if (u + k - 1 > m) {
        puts ("NO");
        return 0;
    }
    for (int i = 0 ; i < k ; i ++) {
        if (gcd (row , u + i) != a[i]) {
            puts ("NO");
            return 0;
        }
    }
    puts ("YES");
    return 0;
}