cf338 D GCD Table - EX_CRT

传送门
给出n和m表示矩阵大小,矩阵的值是\(gcd(i,j)\)
再给出k个长度的序列,请问,这个序列是否在矩阵中出现过

对于在n*m的矩阵找,那么必定需要先找到横坐标,然后在这个横坐标里找k个数字
发现如果说横坐标是\(lcm(a_i)\),是可能存在解的
假设这一行存在序列\([x + i, x + i + k - 1]\),那么\((x + i) \% a[i] == 0\)才能存在解
那么久得到了k个同余方程,\(x\equiv -i (\mod a[i])\)
a[i]是不一定两两互质的非负整数,那么找到一个最小x
最后判断下这个区间的值是否是a即可

#include <iostream>
#include <cstdio>
#define ll long long
using namespace std;
const int N = 1e5 + 5;
void ex_gcd(ll a, ll b, ll &d, ll &x, ll &y){
    if(b == 0){
        d = a,x = 1,y = 0;
        return;
    }
    ex_gcd(b, a % b, d, y, x);
    y -= x * (a / b);
}
inline ll mull(ll a, ll b, ll p) {
    return (a * b - (ll)((long double)a / p * b) * p + p) % p;
}
ll ex_china(ll a[], ll m[], int n){//x = a(mod m)
    ll M = m[1];
    ll ans = a[1];
    ll d, x, y;
    for(int i = 2; i <= n; i++){
        ll c = ((a[i] - ans) % m[i] + m[i]) % m[i];
        ex_gcd(M, m[i], d, x, y);
        if(c % d)return -1;//不存在解的情况
        ll mod = m[i] / d;
        x = mull(x, c / d, mod);
        ans += x * M;
        M *= mod;
        ans = (ans % M + M) % M;
    }
    // return ans > 0? ans : ans + M;//注意ans是M倍数时输出M
    return ans;
}
ll gcd(ll a, ll b){
    return b == 0 ? a : gcd(b, a % b);
}
ll LCM(ll a, ll b){
    return a / gcd(a, b) * b;
}
ll x[N], a[N], mm[N];
int main(){
    ll n, m, k;
    scanf("%lld%lld%lld", &n, &m, &k);
    ll lcm = 1;
    for(int i = 1; i <= k; i++) {
        scanf("%lld", &x[i]);
        lcm = LCM(lcm, x[i]);
    }
    if(lcm > n || lcm < 1) {
        printf("NO\n");
    }else {
        for(int i = 1; i <= k; i++) {
            a[i] = -i;
            mm[i] = x[i];
        }
        ll xxx = ex_china(a, mm, k);
        if(xxx < 0 || xxx + k > m) {
            printf("NO\n"); return 0;
        }
        for(ll j = 1; j <= k; j++) {
            if(gcd(lcm, j + xxx) != x[j]) {
                printf("NO\n");
                return 0;
            }
        }
        printf("YES\n");
    }
    return 0;
}
posted @ 2020-08-05 14:08  Emcikem  阅读(92)  评论(0编辑  收藏  举报