​传送门​

CF D. GCD Table_i++

题意:

给你一个n*m的矩阵,第i行j列元素的值为gcd(i,j),现给你一个长度为k的序列,问这个序列是否能和矩阵中某一行连续子串匹配。

思路:

对于CF D. GCD Table_矩阵_02来说,我们可以列出如下式子:CF D. GCD Table_i++_03,由于选取的序列是连续的,又可以列出所有关于CF D. GCD Table_线性代数_04的式子:
CF D. GCD Table_i++_03
CF D. GCD Table_矩阵_06
CF D. GCD Table_线性代数_07
CF D. GCD Table_#define_08
CF D. GCD Table_i++_09
而对于上述式子,我们可以通过得到j的值,再判断对于已得出的j来说,i是否满足条件。
而对于j,我们可以列出下列同余式:
CF D. GCD Table_#define_10
CF D. GCD Table_线性代数_11
CF D. GCD Table_#define_08
CF D. GCD Table_i++_13
变形一下,得:
CF D. GCD Table_#define_10
CF D. GCD Table_#define_15
CF D. GCD Table_#define_08
CF D. GCD Table_线性代数_17
用拓展中国剩余定理去解出j的值,同时得到i的值是“由中国剩余定理合并后的式子中模数的值”,因为此时此刻的模数为CF D. GCD Table_线性代数_18,恰好是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();
}