CF1155C 题解

题目传送门

题目大意:

给定一个长度为 n 的单增序列 a 和一个长度为 m 的序列 b,询问是否存在一个正整数 y 使得 a1a2any (mod p),且 p 在序列 b 中出现过。

思路:

将条件转化一下,得:是否存在一个正整数 y 使得 p(a2a1),p(a3a2)p(anan1),说白了就是我们要寻找的 p 是序列 a 所有相邻项之差的因数。

所以先构造一个差分序列 c,然后求出 c 中所有数的最大公因数 d

引理:

任意 n 个正整数 (n2) 的所有公因数都是这 n 个数的最大公因数的因数。

证明:

先考虑两个数的情况。

设这两个数是 a,b,考虑将它们分解质因数,并将质因数对齐,得:

a=p1a1p2a2pkak

b=p1b1p2b2pkbk

对于 a,b 的任意因数 d,我们也将它分解质因数并对齐,得:

d=p1c1p2c2pkck

注意!这里的 aibi 可能为 0!(因为只是对齐处理,可能并不含此质因子)

根据因数的定义可得:

cimin(ai,bi),i[1,k]

而对于 gcd(a,b),此时有:

ci=min(ai,bi),i[1,k]

也就是取等了!

所以不难得出,a,b 所有公因数都是最大公因数的因数。

那么推广到 n 个数的情况就不难了,请读者自行证明。

其实挺显然的吧。

有了这个引理,我们就只需要找序列 b 中是否存在一个数是 d 的因数即可。

然后就是一些小细节了。

时间复杂度为 O(n+m+log(max{ci}))

Code:

#include <iostream>

using namespace std;

const int N = 300010;
typedef long long ll;
int n, m;
ll a[N], p[N], c[N];

ll gcd(ll a, ll b) {
    if(b == 0) return a;
    return gcd(b, a % b);
}

int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
    for(int i = 1; i <= m; i++) scanf("%lld", &p[i]);
    for(int i = 1; i <= n; i++) c[i] = a[i] - a[i - 1];
    ll d = c[2];
    for(int i = 3; i <= n; i++) 
        d = gcd(d, c[i]);
    bool flag = false;
    ll fac, ans;
    for(int i = 1; i <= m; i++)
        if(d % p[i] == 0) {
            puts("YES");
            flag = true;
            fac = p[i];
            ans = i;
            break;
        }
    if(!flag) {
        puts("NO");
        return 0;
    }
    if(c[1] % fac == 0) printf("%lld %lld", fac, ans);
    else printf("%lld %lld", c[1] % fac, ans);
    return 0;
}
posted @   Brilliant11001  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示