我们依次来考虑 \(i,j\) 需要满足的条件。
首先,既然满足所有 \(1\leq l\leq k\) 满足 \(\gcd(i,j+l-1)=a_l,\) 那么可以合理导出 \(\forall a_l,a_l|i\to \text{lcm}(a)_{i=1}^{k}|i\)
也就是 \(i\) 应当是 \(\text{lcm}\) 的倍数形式。
那么,设最小公倍数为 \(M,\) 设 \(i=k\times M,\) 有一个推论:\(k=1\) 最优。
证明:若 \(k\not =1,\) 则 \(\gcd(i,j+l-1)=\gcd(k\times M,j+l-1)\)
我们发现,\(\gcd\) 的式子里面平白无故多了一个 \(k.\) 同时,假定 \(j\) 满足条件,那么当 \(i\) 取最小的时候,不合法当且仅当 \(\gcd(i,j+l-1)>a_l,\) 而将 \(i\to M\times k\) 并不会将答案变小,所以并不优。
那么 \(i\) 的构造就显然了,直接取最小公倍数即可。
考虑 \(j\) 如何构造。容易发现, \(j\) 需要满足的性质应该是 \(a_l|j+l-1,\) 也就是 \(j+l-1\equiv 0(\bmod a_l)\to j\equiv 1-l(\bmod a_l)\)
于是这就是一堆同余方程组了,但我们还会发现 \(a_l\) 之间并不互质。所以我们需要 ExCRT 来解决。
考虑无解,我们发现,解决方程组只是必要条件,直接带入检验即可。
一些细节:
-
注意解扩展中国剩余定理的时候,方程的解是相对于前 \(k-1\) 个方程的,所以对应解出来的数不能随便模别的数
-
注意到扩展欧几里得的通解形如 \(x=x_0+k\times \frac{c}{\gcd(a,b)}\) 如果我们要让它最小就让它取正数后对 \(\frac{c}{\gcd(a,b)}\) 取模即可
-
这题数据范围大,会爆,需要龟速乘
-
当解要大的时候就算无解了,因为超出了表格的范围
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e4+10;
int n,m,k,a[N],ans1=1,ans2;
inline int gcd(int x,int y){return !y?x:gcd(y,x%y);}
void Exgcd(int a,int b,int &x,int &y){
if(!b){
x=1;y=0;
return;
}
Exgcd(b,a%b,x,y);
int t=x;x=y;y=t-a/b*y;
}
inline int LCM(int x,int y){return x/gcd(x,y)*y;}
inline int Min(int x,int y){return x>y?y:x;}
inline int Max(int x,int y){return x<y?y:x;}
int Mul(int x,int y,int p){
if(y<0)x=-x,y=-y;
int s=0;
while(y){
if(y&1)s=(s+x)%p;
x=(x+x)%p;y>>=1;
}
return s;
}
void solve(int *A,int *b,int len){
int M=b[1];
int xx=0;
for(int i=2;i<=k;++i){
int r=A[i]-xx;
int t,y;
int d=gcd(M,b[i]);
if(r%d!=0){
puts("NO");
exit(0);
}
Exgcd(M,b[i],t,y);
int nM=LCM(M,b[i]);
t=Mul(t,r/d,b[i]/d);
xx=(xx%nM+t%nM*M%nM)%nM;
if(M>m){
puts("NO");
exit(0);
}
M=nM;
xx%=M;xx+=M;xx%=M;
}
xx%=M;xx+=M;xx%=M;
if(xx==0)xx=M;
if(xx>m){
puts("NO");
exit(0);
}
ans2=xx;
for(int i=1;i<=k;++i){
if(gcd(ans1,ans2+i-1)!=a[i]){
puts("NO");
exit(0);
}
}
puts("YES");
}
int num[N];
signed main(){
// freopen("in.txt","r",stdin);
cin>>n>>m>>k;
for(int i=1;i<=k;++i)cin>>a[i];
for(int i=1;i<=k;++i){
ans1=LCM(ans1,a[i]);
if(ans1>n){
puts("NO");
return 0;
}
}
for(int i=1;i<=k;++i)num[i]=(((a[i]-i+1+a[i])%a[i])+a[i])%a[i];
solve(num,a,k);
return 0;
}