传送门
给出n和m表示矩阵大小,矩阵的值是(gcd(i,j))
再给出k个长度的序列,请问,这个序列是否在矩阵中出现过
对于在n*m的矩阵找,那么必定需要先找到横坐标,然后在这个横坐标里找k个数字
发现如果说横坐标是(lcm(a_i)),是可能存在解的
假设这一行存在序列([x + i, x + k]),那么((x + i) \% a[i] == 0)才能存在解
那么久得到了k个同余方程,(xequiv -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
");
}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
"); return 0;
}
for(ll j = 1; j <= k; j++) {
if(gcd(lcm, j + xxx) != x[j]) {
printf("NO
");
return 0;
}
}
printf("YES
");
}
return 0;
}