codeforces 338D GCD Table (扩展中国剩余定理)

D. GCD Table
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Consider a table G of size n × m such that G(i, j) = GCD(i, j) for all 1 ≤ i ≤ n, 1 ≤ j ≤ mGCD(a, b) is the greatest common divisor of numbers a and b.

You have a sequence of positive integer numbers a1, a2, ..., ak. We say that this sequence occurs in table G if it coincides with consecutive elements in some row, starting from some position. More formally, such numbers 1 ≤ i ≤ n and 1 ≤ j ≤ m - k + 1 should exist that G(i, j + l - 1) = al for all 1 ≤ l ≤ k.

Determine if the sequence a occurs in table G.

Input

The first line contains three space-separated integers nm and k (1 ≤ n, m ≤ 10121 ≤ k ≤ 10000). The second line contains k space-separated integers a1, a2, ..., ak (1 ≤ ai ≤ 1012).

Output

Print a single word "YES", if the given sequence occurs in table G, otherwise print "NO".

Examples
input
100 100 5
5 2 1 2 1
output
YES
input
100 8 5
5 2 1 2 1
output
NO
input
100 100 7
1 2 3 4 5 6 7
output
NO
Note

Sample 1. The tenth row of table G starts from sequence {1, 2, 1, 2, 5, 2, 1, 2, 1, 10}. As you can see, elements from fifth to ninth coincide with sequence a.

Sample 2. This time the width of table G equals 8. Sequence a doesn't occur there.




题目大意:给出一个n*m的数表,(i,j)=GCD(i,j).然后给出一个序列a1...ak问序列是否在数表中出现过。

题解:扩展中国剩余定理

首先可以确定行一定是a1...ak的最小公倍数的倍数,如果lcm>n,那么无解。

然后设第一列为x 

x=a1*b1  (其中b表示a1的整数倍,因为a1为x的gcd,所以一定能表示成a1*b1的形式)

x+1=a2*b2

x+2=a3*b3

.....

可以把式子都转换成线性同余方程的形式x=a[i]-i+1 (mod a[i])

用扩展中国剩余定理合并,然后求出解x

如果解出来的x为0,那么需要先加上r,再进行判断。

如果x>m-k+1,则无解。

然后再带入验证一下答案,就可以输出最终判断的结果了。

#include<iostream>  
#include<cstring>  
#include<algorithm>  
#include<cstdio>  
#include<cmath>  
#define N 10003  
#define LL long long   
using namespace std;  
LL n,m,a[N],c[N],r[N];  
int k;  
LL mul(LL a,LL b,LL mod)
{
	LL ans=0; 
	while (b) {
		if (b&1) ans=(ans+a)%mod;
		b>>=1;
		a=(a+a)%mod;
	}
	return ans%mod;
}
LL gcd(LL x,LL y)  
{  
    LL r;  
    while (y) {  
        r=x%y;  
        x=y; y=r;  
    }  
    return x;  
}  
void exgcd(LL a,LL b,LL &x,LL &y)
{
	if (!b) {
		x=1; y=0; return;
	}
	exgcd(b,a%b,x,y);
	LL t=y;
	y=x-(a/b)*y;
	x=t;
}
LL inv(LL a,LL b){
	LL x,y;
	exgcd(a,b,x,y);
	return (x%b+b)%b;
}
bool check(LL a1,LL a2,LL r1,LL r2,LL &aa,LL &rr)  
{  
     LL c=a2-a1; LL d=gcd(r1,r2);
    // cout<<r1<<" "<<r2<<" "<<d<<endl;
	 if (c%d) return 0;
	 c/=d; r1/=d; r2/=d;
	 LL x=inv(r1,r2); c=(c%r2+r2)%r2;
	 rr=r1*r2*d;
	 x=mul(x,c,r2);
	 x=mul(mul(x,r1,rr),d,rr)+a1;
	 aa=(x%rr+rr)%rr;
	 return 1; 
}  
int main()  
{ 
    freopen("a.in","r",stdin); 
    scanf("%I64d%I64d%d",&n,&m,&k);  
    for (int i=1;i<=k;i++) scanf("%I64d",&c[i]);  
    LL lcm=c[1]/gcd(c[1],c[2])*c[2];  
    for (int i=3;i<=k;i++){  
     lcm=lcm/gcd(lcm,c[i])*c[i];  
     if (lcm>n) {  
        printf("NO\n");  
        return 0;  
     }  
    }  
    for (int i=1;i<=k;i++) r[i]=c[i],a[i]=c[i]-i+1;
	LL a1,a2,r1,r2,rr,aa;
	a1=aa=a[1]; r1=rr=r[1];
	for (int i=2;i<=k;i++) {
		a2=a[i]; r2=r[i];
		if (a2<0) a2=(a2%r2+r2)%r2;
		if(!check(a1,a2,r1,r2,aa,rr)) {
			printf("NO\n");
			return 0;
		}
	    a1=aa; r1=rr;
	    //cout<<aa<<" "<<rr<<endl;
	}
	//cout<<aa<<endl;
	if (!aa) aa+=rr;
	if (aa>m-k+1) {
		printf("NO\n");
		return 0;
	}
	for (int i=1;i<=k;i++) {
		LL t=gcd(lcm,aa+i-1);
		if (t!=c[i]) {
			printf("NO\n");
			return 0;
		}
	}
	printf("YES\n");
}  






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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值