【Codeforces Round #196 (Div. 1)】Codeforces 338D GCD Table

来源:互联网 发布:招商证券理财软件下载 编辑:程序博客网 时间:2024/05/23 13:25

题目实际上要求一组(x,y)满足

gcd(x,y+i)=ai+1,0i<k

首先可以找到x的范围,即x=lcmki=1ai
接下来考虑y,可以列出如下的式子yi(modai+1),用中国剩余定理可以解出模lcmki=1下的解。注意这里的模数不互质,但是依然可以解。只需要把方程两两合并,每次合并用扩展欧几里得算法即可。中间运算可能会爆long long,需要快速乘。
接下来只需要把得到的xy进行验证,因为当前得到的xy都是满足上述条件的最小的值,而且已经满足两者有这样的因数,只是有可能gcd比要求的更大。扩大一定倍数后当然更不可能是解。

#include<cstdio>#include<algorithm>using namespace std;#define LL long longconst LL oo=1e17;LL a[10010];LL gcd(LL a,LL b){    return b?gcd(b,a%b):a;}LL mul(LL x,LL y){    double t=(double)x*y;    if (t>oo) return oo;    return x*y;}LL lcm(LL a,LL b){    return mul(a/gcd(a,b),b);}LL exgcd(LL a,LL b,LL &x,LL &y){    if (!b)    {        x=1;        y=0;        return a;    }    LL ret=exgcd(b,a%b,y,x);    y-=a/b*x;    return ret;}LL multi(LL base,LL k,LL mod){    if (k<0)    {        base=-base;        k=-k;    }    LL ret=0;    for (;k;k>>=1,base=(base+base)%mod)        if (k&1) ret=(ret+base)%mod;    return ret;}int main(){    LL n,m,x=1,u,v,v1,w,y,t1,t2,g;    int k;    scanf("%I64d%I64d%d",&n,&m,&k);    for (int i=1;i<=k;i++) scanf("%I64d",&a[i]);    for (int i=1;i<=k;i++)    {        x=lcm(x,a[i]);        if (x>n)        {            printf("NO\n");            return 0;        }    }    u=0;    v=a[1];    for (int i=2;i<=k;i++)    {        g=exgcd(v,a[i],t1,t2);        w=-u-i+1;        if (w%g)        {            printf("NO\n");            return 0;        }        v1=v;        v=v/g*a[i];        u=multi(multi(w/g,t1,v),v1,v)+u;        u%=v;    }    y=(u+v)%v;    if (!y) y+=v;    if (y+k-1>m)    {        printf("NO\n");        return 0;    }    for (int i=1;i<=k;i++)        if (gcd(x,y+i-1)!=a[i])        {            printf("NO\n");            return 0;        }    printf("YES\n");}
0 0