CF D. GCD Table
原创
©著作权归作者所有:来自51CTO博客作者wx636883f8ce969的原创作品,请联系作者获取转载授权,否则将追究法律责任
传送门
题意:
给你一个n*m的矩阵,第i行j列元素的值为gcd(i,j),现给你一个长度为k的序列,问这个序列是否能和矩阵中某一行连续子串匹配。
思路:
对于来说,我们可以列出如下式子:,由于选取的序列是连续的,又可以列出所有关于的式子:
而对于上述式子,我们可以通过得到j的值,再判断对于已得出的j来说,i是否满足条件。
而对于j,我们可以列出下列同余式:
变形一下,得:
用拓展中国剩余定理去解出j的值,同时得到i的值是“由中国剩余定理合并后的式子中模数的值”,因为此时此刻的模数为,恰好是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();
}