Row GCD(差分+辗转相减法)

题目链接
Row GCD

Row GCD
You are given two positive integer sequences a1,…,an and b1,…,bm. For each j=1,…,m find the greatest common divisor of a1+bj,…,an+bj.

Input
The first line contains two integers n and m (1≤n,m≤2e5).

The second line contains n integers a1,…,an (1≤ai≤1e18).

The third line contains m integers b1,…,bm (1≤bj≤1e18).

Output
Print m integers. The j-th of them should be equal to GCD(a1+bj,…,an+bj).

Example
Input
4 4
1 25 121 169
1 2 7 23
Output
2 3 8 24

题目大意:

给定一个长度为n的序列a[],和长度为m的序列b[],求每个a[i],加上b[j]后的gcd(a[0]....a[n])

解法
这道题用到了差分和辗转相减法,
推导过程:
根据辗转相减法可得到
g c d ( a , b ) = g c d ( a , ∣ a − b ∣ ) = g c d ( b , ∣ a − b ∣ ) gcd(a,b)=gcd(a,|a-b|)=gcd(b,|a-b|) gcd(a,b)=gcd(a,ab)=gcd(b,ab)

g c d ( a , b , c ) = g c d ( a , g c d ( b , c ) ) = g c d ( g c d ( a , b ) , c ) gcd(a,b,c)=gcd(a,gcd(b,c))=gcd(gcd(a,b),c) gcd(a,b,c)=gcd(a,gcd(b,c))=gcd(gcd(a,b),c)

g c d ( a [ 1 ] , a [ 2 ] . . . . . . a [ n ] ) = g c d ( a [ 1 ] , g c d ( ∣ a [ 2 ] − a [ 1 ] ∣ , ∣ a [ 3 ] − a [ 1 ] ∣ . . . . . . a [ n ] − a [ 1 ] ) ) gcd(a[1],a[2]......a[n])=gcd(a[1],gcd(|a[2]-a[1]|,|a[3]-a[1]|......a[n]-a[1])) gcd(a[1],a[2]......a[n])=gcd(a[1],gcd(a[2]a[1],a[3]a[1]∣......a[n]a[1]))
可以推出:
g c d ( a [ 1 ] + b [ j ] , a [ 2 ] + b [ j ] . . . . . . a [ n ] + b [ j ] ) = g c d ( a [ 1 ] + b [ j ] , g c d ( ∣ a [ 2 ] − a [ 1 ] ∣ , ∣ a [ 3 ] − a [ 1 ] ∣ . . . . . . a [ n ] − a [ 1 ] ) ) gcd(a[1]+b[j],a[2]+b[j]......a[n]+b[j])=gcd(a[1]+b[j],gcd(|a[2]-a[1]|,|a[3]-a[1]|......a[n]-a[1])) gcd(a[1]+b[j],a[2]+b[j]......a[n]+b[j])=gcd(a[1]+b[j],gcd(a[2]a[1],a[3]a[1]∣......a[n]a[1])),因此我们只需要提前求出 g c d ( ∣ a [ 2 ] − a [ 1 ] ∣ , ∣ a [ 3 ] − a [ 1 ] ∣ . . . . . . a [ n ] − a [ 1 ] ) gcd(|a[2]-a[1]|,|a[3]-a[1]|......a[n]-a[1]) gcd(a[2]a[1],a[3]a[1]∣......a[n]a[1])即可
代码如下:

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=2e5+10;
ll q[N];
int n,m;
ll g=0;
ll gcd(ll a,ll b)
{
	return b?gcd(b,a%b):a;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++) scanf("%lld",&q[i]);
	sort(q,q+n);
	for(int i=1;i<n;i++)
		g=gcd(g,q[i]-q[0]);
	while(m--)
	{
		ll x;
		scanf("%lld",&x);
		printf("%lld ",gcd(g,q[0]+x));
	}
}

相似例题
公因子

牛妹是一个喜欢公因子的女孩子。
定义 n 个整数a1,a2,....,an的gcd 为最大的正整数 p 满足对于所有1<=i<=n ,p 整除ai
牛妹有一个长度为 n 的整数序列a1,a2,....,an。她希望能求出一个非负整数 x,使得a1+x,a2+x,....,an+x的gcd最大。
牛妹不满足于只求出这个最大的gcd,所以她希望你还能帮她求出在满足gcd 最大时最小的 x。

输入描述

第一行一个整数n(2<=n<=1e6),表示牛妹的序列长度。
第二行n个整数a1,a2,......,an(-1e18<=ai<=1e18),表示牛妹的序列。
输入保证存在最大的gcd。这里保证了输入数据的合理性,不会出现a[]中所有元素都相同的情况

输出描述

输出一行两个整数,分别表示最大的gcd和满足gcd最大时,最小的x。

示例

输入
3 
-3 1 3
输出
2 1

分析:
这道题和上面的例题差不多,只是在最后需要通过判断q[0]的值来确定x的值
代码如下

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=1e6+10;
ll q[N];
ll g=0;
ll gcd(ll a,ll b){
	return b?gcd(b,a%b):a;
}
int main(){
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++) scanf("%lld",&q[i]);
	for(int i=1;i<n;i++) g=gcd(g,abs(q[i]-q[0]));
	printf("%lld ",g);
    if(q[0]>=0)
		printf("%lld\n",((g-q[0])%g+g)%g);
    else
		printf("%lld\n",abs(q[0])%g);
	return 0;
}

还有一道难一些的题,用到了树状数组
4302 Interval GCD

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chp的博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值