题意:
给你一个n*m的矩阵,第i行j列元素的值为gcd(i,j),现给你一个长度为k的序列,问这个序列是否能和矩阵中某一行连续子串匹配。
思路:
对于
a
1
a_1
a1来说,我们可以列出如下式子:
g
c
d
(
i
,
j
)
=
a
1
gcd(i,j)=a_1
gcd(i,j)=a1,由于选取的序列是连续的,又可以列出所有关于
a
1
到
a
k
a_1到a_k
a1到ak的式子:
g
c
d
(
i
,
j
)
=
a
1
gcd(i,j)=a_1
gcd(i,j)=a1
g
c
d
(
i
,
j
+
1
)
=
a
2
gcd(i,j+1)=a_2
gcd(i,j+1)=a2
g
c
d
(
i
,
j
+
2
)
=
a
3
gcd(i,j+2)=a_3
gcd(i,j+2)=a3
.
.
.
.
.
.
......
......
g
c
d
(
i
,
j
+
k
−
1
)
=
a
k
gcd(i,j+k-1)=a_k
gcd(i,j+k−1)=ak
而对于上述式子,我们可以通过得到j的值,再判断对于已得出的j来说,i是否满足条件。
而对于j,我们可以列出下列同余式:
j
%
a
1
=
0
j\%a_1=0
j%a1=0
(
j
+
1
)
%
a
2
=
1
(j+1)\%a_2=1
(j+1)%a2=1
.
.
.
.
.
.
......
......
(
j
+
k
−
1
)
%
a
k
=
k
−
1
(j+k-1)\%a_k=k-1
(j+k−1)%ak=k−1
变形一下,得:
j
%
a
1
=
0
j\%a_1=0
j%a1=0
j
%
a
2
=
−
1
j\%a_2=-1
j%a2=−1
.
.
.
.
.
.
......
......
j
%
a
k
=
−
k
+
1
j\%a_k=-k+1
j%ak=−k+1
用拓展中国剩余定理去解出j的值,同时得到i的值是“由中国剩余定理合并后的式子中模数的值”,因为此时此刻的模数为
l
c
m
(
a
1
,
a
2
.
.
.
.
.
.
a
k
)
lcm(a_1,a_2......a_k)
lcm(a1,a2......ak),恰好是i的值。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
void exgcd(ll a,ll b,ll &x,ll &y)
{
if(b==0)
{
x = 1,y = 0;
return;
}
exgcd(b,a%b,x,y);
ll t = x;
x = y;
y = t-a/b*y;
}
ll a[10010];
ll n,m,k;
void solve()
{
ll mod = a[1],now = 0;
int f = 1;
for(int i = 2; i <= k; i++)
{
ll yu = -(i-1);
ll g = __gcd(mod,a[i]);
ll d = yu-now;
if(d%g!=0)
{
f = 0;
break;
}
ll x,y;
exgcd(mod,a[i],x,y);
x = (__int128)x*d/g%(a[i]/g);
now = (__int128)mod*x+now;
mod = (__int128)mod*a[i]/g;
now = (now%mod+mod)%mod;
}
if(!now)now = mod;
if(f && mod <= n && now+k-1 <= m)
{
for(int i = 1; i <= k; i++)
{
if(__gcd(mod,now+i-1) != a[i])
{
cout<<"NO"<<endl;
return;
}
}
cout<<"YES"<<endl;
}
else cout<<"NO"<<endl;
}
int main()
{
cin>>n>>m>>k;
for(int i = 1; i <= k; i++)
{
cin>>a[i];
}
solve();
}