CF338D GCD Table

题目描述

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

你有一个长度为 k k k 的数列 a a a

询问是否存在 x , y x,y x,y 1 ≤ x ≤ n , 1 ≤ y + k − 1 ≤ m 1 \leq x \leq n, 1 \leq y + k-1\leq m 1xn,1y+k1m,满足 ∀ 1 ≤ l ≤ k , gcd ⁡ ( x , y + l − 1 ) = a l \forall 1 \leq l \leq k,\gcd(x,y+l-1)=a_l 1lk,gcd(x,y+l1)=al

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

对于 100 % 100\% 100% 的数据,保证 1 ≤ n ≤ 1 0 12 , 1 ≤ m ≤ 1 0 12 , 1 ≤ k ≤ 1 0 5 , 1 ≤ a i ≤ 1 0 12 1 \leq n \leq 10^{12},1 \leq m \leq 10^{12}, 1 \leq k \leq 10^5,1 \leq a_i \leq 10^{12} 1n1012,1m1012,1k105,1ai1012

解题思路

前置知识:exCRT

根据题意显然可以列出:
{ gcd ⁡ ( x , y + 1 − 1 ) = a 1 gcd ⁡ ( x , y + 2 − 1 ) = a 2 ⋯ gcd ⁡ ( x , y + k − 1 ) = a k \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(x,y+11)=a1gcd(x,y+21)=a2gcd(x,y+k1)=ak
我们知道 gcd ⁡ ( a , b ) = c \gcd(a,b)=c gcd(a,b)=c,显然有: a = p 1 c , b = p 2 c , p 1 ∤ p 2 a=p_1c,b=p_2c,p_1\nmid p_2 a=p1c,b=p2c,p1p2

即:
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 ac,bcxai,y+i1ai
即:

x ≡ 0 ( m o d a i ) x \equiv 0 \pmod{a_i} x0(modai)

y ≡ 1 − i ( m o d a i ) y \equiv 1-i \pmod{a_i} y1i(modai)

整理出:
{ y ≡ ( 1 − 1 ) ( m o d a 1 ) y ≡ ( 2 − 1 ) ( m o d a 2 ) ⋯ y ≡ ( k − 1 ) ( m o d a k ) \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} y(11)(moda1)y(21)(moda2)y(k1)(modak)
显然 a i a_i ai 之间不一定互质,所以我们直接使用拓展中国剩余定理求解即可,这样我们就可以求出一个合法的 y y y

显然 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 以后验证是否在范围内即可。

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

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值