CF338D GCD Table

题目描述

给你 n,m,k,pn,m,k,p。

你有一个长度为 kk 的数列 aa。

询问是否存在 x,yx,y,1≤x≤n,1≤y+k−1≤m1 \leq x \leq n, 1 \leq y + k-1\leq m,满足 ∀1≤l≤k,gcd⁡(x,y+l−1)=al\forall 1 \leq l \leq k,\gcd(x,y+l-1)=a_l。

若存在,输出 YES,否则,输出 NO。

对于 100%100\% 的数据,保证 1≤n≤1012,1≤m≤1012,1≤k≤105,1≤ai≤10121 \leq n \leq 10^{12},1 \leq m \leq 10^{12}, 1 \leq k \leq 10^5,1 \leq a_i \leq 10^{12}。

解题思路

前置知识:exCRT。

根据题意显然可以列出:

{gcd⁡(x,y+1−1)=a1gcd⁡(x,y+2−1)=a2⋯gcd⁡(x,y+k−1)=ak\begin{cases}\gcd(x,y+1-1)=a_1 \\ \gcd(x,y+2-1)=a_2 \\ \cdots \\ \gcd(x,y+k-1)=a_k\end{cases}

我们知道 gcd⁡(a,b)=c\gcd(a,b)=c,显然有:a=p1c,b=p2c,p1∤p2a=p_1c,b=p_2c,p_1\nmid p_2,

即:

a∣c,b∣c⇒x∣ai,y+i−1∣aia \mid c,b \mid c \Rightarrow x \mid a_i,y + i-1 \mid a_i

即:

x≡0(modai)x \equiv 0 \pmod{a_i}

和

y≡1−i(modai)y \equiv 1-i \pmod{a_i}

整理出:

{y≡(1−1)(moda1)y≡(2−1)(moda2)⋯y≡(k−1)(modak)\begin{cases}y \equiv (1-1) \pmod{a_1} \\ y \equiv (2-1) \pmod{a_2} \\ \\ \cdots \\ y \equiv (k-1) \pmod{a_k}\end{cases}

显然 aia_i 之间不一定互质,所以我们直接使用拓展中国剩余定理求解即可,这样我们就可以求出一个合法的 yy。

显然 xx 可以整除所有的 aia_i ,那么满足条件的最小的 xx 显然是 lcm{ai}\text{lcm}\{a_{i}\}。

求出 x,yx,y 以后验证是否在范围内即可。

时间复杂度 O(nlog⁡n)\mathcal{O}(n \log n)。

CODE

#include <bits/stdc++.h>

using namespace std;

#define int long long

int read()
{
    int f = 1, x = 0;
    char c = getchar();
    while(c < '0' || c > '9'){if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9'){x = x * 10 + c - '0'; c = getchar();}
    return f * x;
}

const int maxn = 100010;

int n, p;

int a, b;

int Lcm = 1;

int ai[maxn], bi[maxn];

int js(int x, int mod)
{
	if(x < mod) return x;
	return x % mod + mod;
}

int gcd(int a, int b)
{
	if(!b) return a;
	return gcd(b, a % b);
}

int lcm(int a, int b)
{
	return a / gcd(a, b) * b;
}

int mul(int a, int b, int mod)
{
	if(b < 0) a = -a, b = -b;
    int res = 0;
    while(b > 0)
    {
        if(b & 1) res = (res + a) % mod;
        a = (a + a) % mod;
        b >>= 1;
    }
    return res;
}

int exgcd(int a, int b, int &x, int &y)
{
    if(b == 0){x = 1; y = 0; return a;}
    int gcd = exgcd(b, a % b, x, y);
    int tp = x;
    x = y; y = tp - a / b * y;
    return gcd;
}

int excrt()
{
    int x, y, k;
    int M = bi[1], ans = ai[1];
    for(int i = 2; i <= n; ++i)
    {
        int a = M, b = bi[i], c = (ai[i] - ans % b + b) % b;
        int gcd = exgcd(a, b, x, y), bg = b / gcd;
        if(c % gcd != 0) return -1;
        x = mul(x, c / gcd, bg);
        ans += x * M;
        M *= bg;
        ans = (ans % M + M) % M;
    }
    ans = (ans % M + M) % M;
    if(ans == 0) ans = M;
    return ans;
}

int phi(int x)
{
	int o = x;
	for(int i = 2; i * i <= x; ++i)
	{
		if(x % i == 0)
		{
			while(x % i == 0) x /= i;
			o = o / i * (i - 1);
		}
	}
	if(x > 1) o = o / x * (x - 1);
	return o;
}

int qpow(int x, int y, int mod)
{
	int res = 1ll;
	while(y)
	{
		if(y & 1ll) res = js(res * x, mod);
		x = js(x * x, mod);
		y >>= 1ll;
	}
	return x;
}

int solve(int l, int r, int mod)
{
	if(l == r || mod == 1) return js(l, mod);
	return qpow(l, solve(l + 1, r, phi(mod)), mod);
}

signed main()
{
    a = read(), b = read(), n = read(), p = read();
    for(int i = 1; i <= n; ++i)
    {
    	bi[i] = read();
		ai[i] = (1 - i + bi[i]) % bi[i];
		Lcm = lcm(Lcm, bi[i]);
	}
	if(n > b) return puts("NO"), 0;
	int x = Lcm, y = excrt();
	if(y == -1) return puts("NO"), 0;
	for(int i = 1; i <= n; ++i)
		if(gcd(x, y + i - 1) != bi[i])
			return puts("NO"), 0;
	if(y < 1 || x < 1 || y + n - 1 > b || x > a) 
		return puts("NO"), 0;
	puts("YES");
	return 0;
}
posted @ 2021-12-19 17:40  蒟蒻orz  阅读(43)  评论(0)    收藏  举报  来源