D. GCD Table (338D)
D. GCD Table (338D)
tag: exCRT exGCD
题目链接
题意:
给你一个'n*m'的矩阵,格子[i,j]的值G[i][j] = gcd(i,j)
再给你一串长度为k的序列a
问你能否在矩阵的某一行中,找到连续的k个格子,满足下列条件
- 设第一个格子位置为[x,y]
- 使 g[x][y] = a[1], g[x][y+1] = a[2] ... g[x][y+k-1] = a[k]
输出“YES"或"NO"即可
做法:
本篇题解需要提前学会exgcd和excrt,我也是初学,推荐如下学习资料
博客
视频
首先我们来分析一下x
// gcd(x,y+i-1) = a[i],
// a[i] 都是x的因子,所以x一定是a[i]公倍数的倍数
// x = lcm(a[1],a[2]...a[k])*N
接着分析一下y
// y%a[1] = 0, (y+1)%a[2] = 0, (y+2)%a[3] = 0 ...
// (y+1)%a[2] = 0 -> y%a[2] = a[2]-1
// y%a[2] = a[2]-1
// y%a[3] = a[3]-1
// ...
// y%a[k] = a[k]-k+1 注意 a[k]-k+1不一定落在0到a[k]-1之间,记得取模
// 由此我们可以得到y的同余方程组,利用excrt求特解即可
// 模数mo[i] = a[i], 余数re[i] = (mo[k]-k+1+mo[k])%mo[k]
按照上面的思路我们就可以求出答案了,但再唠几句
我们通过excrt可以求得y的特解ans,y的通解可以表示为
LCM = lcm(mo[1],mo[2],..mo[k])
y%LCM = ans%LCM
同时我们知道x是LCM的倍数,不妨让x = LCM , 那么 y%x = ans%x
根据同余性质推得 gcd(ans,x) = gcd(y,x)
代码:
#define fst std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout << std::fixed << std::setprecision(20)
#define le "\n"
#define ll long long
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+50;
ll mo[N],re[N]; //模数、余数
ll n,m,k;
inline ll gcd(ll n,ll m){
return (m ? gcd(m,n%m) : n);
}
inline ll lcm(ll n,ll m){
return n/gcd(n,m)*m;
}
inline ll qMul(ll n,ll m,ll mod){//龟速乘防炸
if(m<0) n = -n,m = -m;
ll res = 0;
while(m){
if(m&1) res = (res+n)%mod;
n = (n+n)%mod;
m>>=1;
}
return res%mod;
}
ll exgcd(ll a,ll b,ll &x,ll &y){
if(b==0){
x = 1;
y = 0;
return a;
}
ll q = exgcd(b,a%b,y,x); //交换x,y
y -= a/b*x;
return q;
}
int main() {
cin>>n>>m>>k;
ll Lcm = 1;
for(int i=1;i<=k;i++){
cin>>mo[i];
Lcm = lcm(mo[i],Lcm);
if(Lcm>n){
cout<<"NO"<<le;
return 0;
}
re[i] = ((mo[i]-i+1)+mo[i])%mo[i];
}
ll ans = re[1],M = mo[1]; // ans式子特解,M为模数的lcm
ll x,y;
for(int i=2;i<=k;i++){
ll mi = mo[i],res = ((re[i]-ans)%mi+mi)%mi;
ll gcd = exgcd(M,mi,x,y);
if(res%gcd!=0){
cout<<"NO"<<le;
return 0;
}
x = qMul(x,res/gcd,mi);
ans += x*M;
M = mi/gcd*M;
ans = (ans%M+M)%M;
}
if(ans==0) ans = M;//这里比较细节,我们期望ans落在1~M中而不是0~M-1中,最后特判一下就行
if(ans+k-1>m||ans<1){0
cout<<"NO"<<le;
return 0;
}
for(int i=1;i<=k;i++){
if(gcd(Lcm,ans+i-1)!=mo[i]){
cout<<"NO"<<le;
return 0;
}
}
cout<<"YES"<<le;
return 0;
}

浙公网安备 33010602011771号