CF338D GCD Table(拓展中国剩余定理,细节处理,2900分)
作者:互联网
整理的算法模板合集: ACM模板
实际上是一个全新的精炼模板整合计划
CF338D GCD Table(拓展中国剩余定理,细节处理,2900分)
Problem
有一张 n × m n\times m n×m 的表格 G G G,第 i i i 行第 j j j 列的元素是 G ( i , j ) = gcd ( i , j ) G(i,j)=\gcd(i,j) G(i,j)=gcd(i,j) 。给定一个长度为 k k k 的序列 a i a_i ai ,询问是否存在 x , y x,y x,y,满足 ∀ i , 1 ≤ i ≤ k , G ( x , y + i − 1 ) = gcd ( x , y + i − 1 ) = a i \forall i,1\le i\le k,G(x,y+i-1)=\gcd(x,y+i-1)=a_i ∀i,1≤i≤k,G(x,y+i−1)=gcd(x,y+i−1)=ai (即问是否有在表格范围内的解 ( x , y ) (x,y) (x,y) )。
数据范围: 1 ≤ n , m ≤ 1 0 12 , 1 ≤ k ≤ 1 0 4 , 1 ≤ a i ≤ 1 0 12 1\le n,m\le 10^{12},1\le k\le 10^4,1\le a_i\le 10^{12} 1≤n,m≤1012,1≤k≤104,1≤ai≤1012
Solution
根据题意显然可以列出:
{ gcd ( x , y + 1 − 1 ) = a 1 gcd ( x , y + 2 − 1 ) = a 2 ⋯ gcd ( x , y + k − 1 ) = a k \left\{ \begin{aligned} \gcd(x,y+1-1) & = & a_1 \\ \gcd(x,y+2-1) & = & a_2 \\ \cdots\\ \gcd(x,y+k-1)& = & a_k \end{aligned} \right. ⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧gcd(x,y+1−1)gcd(x,y+2−1)⋯gcd(x,y+k−1)===a1a2ak
我们知道 gcd ( a , b ) = c \gcd(a,b) =c gcd(a,b)=c,经典套路,显然有: a = k 1 c , b = k 2 c , k 1 ∤ k 2 a=k_1c,b=k_2c,k_1\nmid k_2 a=k1c,b=k2c,k1∤k2
即:
a
∣
c
,
b
∣
c
⇒
x
∣
a
i
,
y
+
i
−
1
∣
a
i
a\mid c,b\mid c\Rightarrow x\mid a_i,y+i-1\mid a_i
a∣c,b∣c⇒x∣ai,y+i−1∣ai
即:
x ≡ 0 m o d a i y ≡ ( 1 − i ) m o d a i \begin{aligned}&x\equiv0 \bmod a_i&\\&y\equiv(1-i)\bmod a_i\end{aligned} x≡0modaiy≡(1−i)modai
所以我们可以列出一个同余方程组:
{ y ≡ ( 1 − 1 ) m o d a 1 y ≡ ( 1 − 2 ) m o d a 2 ⋯ y ≡ ( 1 − k ) m o d a k \left\{ \begin{aligned}&y\equiv(1-1)\bmod a_1&\\&y\equiv(1-2)\bmod a_2\\&\ \ \ \ \ \ \ \ \ \ \ \ \ \ \cdots&\\&y\equiv(1-k)\bmod a_k\end{aligned} \right. ⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧y≡(1−1)moda1y≡(1−2)moda2 ⋯y≡(1−k)modak
显然 a i a_i ai 不一定是质数,所以我们直接使用拓展中国剩余定理求解即可,这样我们就可以求出一个合法的 y y y。
那么如何求出最小的(不容易越界)且合法的 x x x 呢,显然 x x x 可以整除所有的 a i a_i ai,那么满足条件的最小的 x x x 显然是 lcm { a i } \text{lcm}\{ a_{i} \} lcm{ai}。
求出 x , y x,y x,y 以后验证一下开头列出来的 gcd \gcd gcd 是否完全相同,以及 G ( x , y + i − 1 ) G(x,y+i-1) G(x,y+i−1) 中的 ( x , y + i − 1 ) (x,y+i-1) (x,y+i−1) 是否在 G G G 函数的定义域内即可。(我们只需要判断 x , y + i − 1 , y + k − 1 x,y+i-1,y+k-1 x,y+i−1,y+k−1 是否越界即可)
Hint
-
这里如果给定的模数均为 1 1 1 的话,直接用
excrt
板子求出来的是 0 0 0 ,此时应该是答案取任意值均可,但是这里如果答案取 0 0 0 的话 y < 1 y<1 y<1 会判负,实际上是有解的,所以这里要特判一下。 -
龟速乘的时候,如果乘的是负数的话需要 a , b a,b a,b 同时取反,否则会死循环hhh
Code
// Problem: D. GCD Table
// Contest: Codeforces - Codeforces Round #196 (Div. 1)
// URL: https://codeforces.com/problemset/problem/338/D
// Memory Limit: 256 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
#define int long long
using namespace std;
using ll = long long;
const int N = 1e4 + 7;
int n, m, k, t;
int a[N], LCM;
int ai[N], bi[N];
template <typename T> inline void read(T& t) {
int f = 0, c = getchar(); t = 0;
while (!isdigit(c)) f |= c == '-', c = getchar();
while (isdigit(c)) t = t * 10 + c - 48, c = getchar();
if (f) t = -t;
}
template <typename T> void print(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) print(x / 10);
putchar(x % 10 + 48);
}
int gcd(int a, int b)
{
if(b == 0) return a;
return gcd(b, a % b);
}
int lcm(int a, int b)
{
return a / gcd(a, b) * b;
}
int exgcd(int a, int b, int &x, int &y)
{
if(b == 0) {
x = 1, y = 0;
return a;
}
int d = exgcd(b, a % b, x, y);
int z = x;
x = y, y = z - a / b * y;
return d;
}
int mul(int a, int b, int c)
{
if(b < 0) a = - a, b = - b;
int res = 0;
while(b) {
if(b & 1) res = (res + a) % c;
a = (a + a) % c;
b >>= 1;
}
return res;
}
ll excrt(int n)
{
ll x, y, k;
ll M = bi[1], ans = ai[1];
for(int i = 2; i <= n; ++ i) {
ll a = M, b = bi[i], c = (ai[i] - ans % b + b) % b;
ll d = exgcd(a, b, x, y);
ll bg = b / d;
if(c % d != 0) return -1;
x = mul(x, c / d, bg);
ans += x * M;
M *= bg;
ans = (ans % M + M) % M;
}
ans = (ans % M + M) % M;
if(ans == 0) ans = M;//ans = 1;
return ans;
}
signed main()
{
LCM = 1;
read(n), read(m), read(k);
for(int i = 1; i <= k; ++ i) {
read(a[i]);
LCM = lcm(LCM, a[i]);
}
if(k > m) return puts("NO"), 0;
for(int i = 1; i <= k; ++ i) {
bi[i] = a[i];
ai[i] = (1 - i + a[i]) % a[i];
}
int x = LCM, y = excrt(k);
if(y == -1) return puts("NO"), 0;
for(int i = 1; i <= k; ++ i) {
if(gcd(x, y + i - 1) != a[i])
return puts("NO"), 0;
}
if(y < 1 || x < 1 || y + k - 1 > m || x > n)
return puts("NO"), 0;
return puts("YES"), 0;
}
标签:2900,return,GCD,int,CF338D,ai,le,ans,gcd 来源: https://blog.csdn.net/weixin_45697774/article/details/117964108