Codeforces 338 D. GCD Table

http://codeforces.com/problemset/problem/338/D

 

题意:

有一张n*m的表格,其中第i行第j列的数为gcd(i,j)

给出k个数

问在这张表格中是否 有某一行中连续的某一部分 就是 这k个数

 

题意转化:

是否存在 一对i,j

满足gcd(i,j)=a1,gcd(i,j+1)=a2,…… gcd(i,j+k-1)=ak

直观上感觉:

i要满足的必要条件是 i |  lcm(a1,a2……ak)

j要满足的必要条件是

j= a1*k1,j+1=a2*k2……,j+k-1=ak*k_k

相当于

j ≡ 0 mod a1

j ≡ -1 mod a2

……

j≡ -(k-1) mod ak

利用扩展中国剩余定理可以求出 满足条件的最小的j

我们令i=lcm(a1,a2……ak)

去检验 是否满足 gcd(i,j+m-1)= a_m  m∈[1,k]

若满足条件输出YES,否则输出NO

 

为什么用满足必要条件的最小的i和j检验?

 

证明 i= lcm(a1,a2……ak)是唯一满足要求的i:

若还存在一个 i*x  满足条件,那么

将 i , i*x,j 质因数分解,存在一个 p^k 能整除i*x、j,不能整除i

∵ i= lcm(a1,a2……ak)

∴i的质因数分解的任意一项 必须能整除 a中的某一个

而 p^k 不能整除a 中的任意一个,否则i的质因数分解包含 p^k

 

证明 满足 j ≡ -(h-1) mod a[h] 的最小的j一定满足要求

若存在一个j*x 满足条件,而j不满足条件

即 存在一个h,满足 gcd(i,j+h-1)< a[h],gcd(i,j*x+h-1)= a[h]

将 j,j*x ,a[h]质因数分解,j*x 中 存在一个p^k2,满足

j 中 为 p^k1,a[h] 中为 p^k2 , 且 k1<k2

∵  j ≡ -(h-1) mod a[h] 

即 j= a[h]*s - h+1

∴ j+h-1 = a[h]*s,所以k1>=k2

所以 最小的j一定满足要求

 

#include<cstdio>
#include<iostream>

using namespace std;

typedef long long LL;

#define N 10001

LL a[N];

LL n1,a1;

LL lcm;

template<typename T>
void read(T &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}

LL gcd(LL a,LL b) { return !b ? a : gcd(b,a%b); }

bool judge_lcm(int k,LL n)
{
    lcm=1;
    for(int i=1;i<=k;++i) 
    {
        lcm=lcm/gcd(lcm,a[i])*a[i];
        if(lcm>n) return false;
    }
    return true;
}

void exgcd(LL a,LL b,LL &x,LL &y)
{
    if(!b) { x=1; y=0; return;}
    exgcd(b,a%b,y,x); y-=a/b*x;
}

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

LL merge(LL n2,LL a2)
{
    LL d=gcd(n1,n2),c=a2-a1;
    if(c%d) return -1;
    LL x,y;
    exgcd(n1/d,n2/d,x,y);
    LL mod=n2/d;
    x=(x%mod+mod)%mod;
    LL k=(mul(c/d,x,mod)%mod+mod)%mod;
    a1=(a1+n1*k%(mod*n1))%(mod*n1);
    n1*=mod;
    return a1;
}

int main()
{
    LL n,m; int k;
    read(n); read(m); read(k);
    for(int i=1;i<=k;++i) read(a[i]);
    if(!judge_lcm(k,n))
    {
        puts("NO");
        return 0;
    }
    n1=a[1]; a1=0;
    LL j=a1;
    for(int i=2;i<=k;++i)
    {
        j=merge(a[i],a[i]-(i-1));
        if(j==-1) { puts("NO"); return 0; }
    }
    if(!j) j=lcm;
    if(j+k-1>m) { puts("NO"); return 0;}
    for(int i=1;i<=k;++i) 
        if(gcd(lcm,j+i-1)!=a[i]) { puts("NO"); return 0; }
    puts("YES");
}

 

转载于:https://www.cnblogs.com/TheRoadToTheGold/p/8459432.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值