您的位置:首页 > 其它

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

2017-05-05 19:42 381 查看
题目实际上要求一组(x,y)满足

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

首先可以找到x的范围,即x=lcmki=1ai。

接下来考虑y,可以列出如下的式子y≡−i(modai+1),用中国剩余定理可以解出模lcmki=1下的解。注意这里的模数不互质,但是依然可以解。只需要把方程两两合并,每次合并用扩展欧几里得算法即可。中间运算可能会爆long long,需要快速乘。

接下来只需要把得到的x和y进行验证,因为当前得到的x和y都是满足上述条件的最小的值,而且已经满足两者有这样的因数,只是有可能gcd比要求的更大。扩大一定倍数后当然更不可能是解。

#include<cstdio>
#include<algorithm>
using namespace std;
#define LL long long
const 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");
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: