题目链接
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,∣a−b∣)=gcd(b,∣a−b∣)
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