CF338D GCD Table

题目描述

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

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

询问是否存在 x,yx,y1xn,1y+k1m1 \leq x \leq n, 1 \leq y + k-1\leq m,满足 1lk,gcd(x,y+l1)=al\forall 1 \leq l \leq k,\gcd(x,y+l-1)=a_l

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

对于 100%100\% 的数据,保证 1n1012,1m1012,1k105,1ai10121 \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+11)=a1gcd(x,y+21)=a2gcd(x,y+k1)=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,p1p2a=p_1c,b=p_2c,p_1\nmid p_2

即:

ac,bcxai,y+i1aia \mid c,b \mid c \Rightarrow x \mid a_i,y + i-1 \mid a_i

即:

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

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

整理出:

{y(11)(moda1)y(21)(moda2)y(k1)(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(nlogn)\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  阅读(1)  评论(0编辑  收藏  举报  来源