「CF338D」GCD Table
problem
题意
有一张n×m的表,其中第i行第j列的元素是gcd(i,j)。
给定一个长度为k的序列a,询问在表中是否存在一对(x,y)使得∀i∈[1,k],ai=gcd(x,y+i−1)
Solutions
以下引自@siyuan的题解
Solution
由于我们要保证 gcd(x,y)=ai,显然 lcm(a1,a2,…,ak)∣x。
我们尝试证明:如果有解,那么x的值可以为lcm(a1,a2,…,ak)。
如果有解,且x=K×lcm(a1,a2,…,ak),那么意味着gcd(K,y)=0,这样一来我们给y平白无故地增加了限制。因此如果 x=K×lcm(a1,a2,…,ak)时有解,那么在 x=lcm(a1,a2,…,ak)时一定也有解。
在确定了x的值之后,还需要满足ai∣y+i−1,即满足下列同余方程:
⎩⎨⎧y=0(moda1)y=−1(moda2)⋮y=−k+1(modak)
这个方程显然可以通过扩展中国剩余定理来求解y即可。
但是我们发现,求出y之后的解 (x,y)
不一定就是合法的,这是为什么呢?
其实我们通过这样的思路,推导出解只满足必要性,而不满足充分性。因此我们还需要将(x,y)代入 gcd(x,y+i−1)=ai(1≤i≤k)验证。
时间复杂度:O(klogai)
Code
没想清楚细节WA了好几发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| #include <cstdio> #include <cstdlib> #include <cmath> #include <algorithm> #include <cstring> #include <iostream> using namespace std; typedef long long ll;
template <typename T>void read(T &t) { t=0;int f=0;char c=getchar(); while(!isdigit(c)){f|=c=='-';c=getchar();} while(isdigit(c)){t=t*10+c-'0';c=getchar();} if(f)t=-t; }
const int maxk=10000+5; ll n,m; int K; ll X,Y; ll a[maxk],r[maxk];
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a; }
ll exgcd(ll a,ll b,ll &x,ll &y) { if(!b) { x=1,y=0; return a; } ll xx,yy,re=exgcd(b,a%b,xx,yy); x=yy; y=xx-a/b*yy; return re; }
ll excrt() { ll M=a[1],R=r[1]; for(register int i=2;i<=K;++i) { ll k1,k2,g=exgcd(M,a[i],k1,k2); if((r[i]-R)%g)return -1; k1=(r[i]-R)/g*k1%a[i]; R+=k1*M; M=M/g*a[i]; R%=M; } return (R-1+M)%M+1; }
int main() { read(n),read(m),read(K); read(a[1]),r[1]=0,X=a[1]; for(register int i=2;i<=K;++i) { read(a[i]),r[i]=1-i; ll g=gcd(X,a[i]); X=X/g*a[i]; } Y=excrt(); if(X>n || Y+K-1>m || Y<1) { printf("NO"); return 0; } for(register int i=1;i<=K;++i) if(gcd(X,Y+i-1)!=a[i]) { printf("NO"); return 0; } printf("YES"); return 0; }
|