根据题意,我们可以得到一个式子:
gcd
i
=
h
1
h
2
(
gcd
j
=
w
1
w
2
(
a
i
+
b
j
)
)
\gcd_{i=h_1}^{h_2}(\gcd_{j=w_1}^{w_2}(a_i+b_j))
i=h1gcdh2(j=w1gcdw2(ai+bj))
自然而然地,我们的暴力思路就有了,直接根据上面这个式子直接进行 gcd \gcd gcd 运算,时间复杂度为 O ( q n 2 ) O(qn^2) O(qn2) 。
然而这个题的数据范围是 1 ≤ N , Q ≤ 2 × 1 0 5 {1\leq N,Q\leq 2\times 10^5} 1≤N,Q≤2×105,所以我们需要想一下其他思路。
在我们学习的 gcd ( a , b ) {\gcd(a,b)} gcd(a,b) 的解法中,有一种是更相减损法 gcd ( a , b ) = gcd ( a , b − a ) {\gcd(a,b)=\gcd(a,b-a)} gcd(a,b)=gcd(a,b−a)。 这时我们再来根据这个知识点思考这道题:
原式:
gcd
(
a
h
1
+
b
w
1
,
a
h
1
+
b
w
1
+
1
,
a
h
1
+
b
w
1
+
2
,
⋯
,
a
h
1
+
b
w
2
)
gcd
(
a
h
1
+
1
+
b
w
1
,
a
h
1
+
1
+
b
w
1
+
1
,
a
h
1
+
1
+
b
w
1
+
2
,
⋯
,
a
h
1
+
1
+
b
w
2
)
⋮
gcd
(
a
h
2
+
b
w
1
,
a
h
2
+
b
w
1
+
1
,
a
h
2
+
b
w
1
+
2
,
⋯
,
a
h
2
+
b
w
2
)
\begin{aligned} &\gcd(a_{h_1}+b_{w_1},\text{ }a_{h_1}+b_{w_1+1},\text{ }a_{h_1}+b_{w_1+2},\text{ }\cdots,\text{ }a_{h_1}+b_{w_2})\\ &\gcd(a_{h_1+1}+b_{w_1},\text{ }a_{h_1+1}+b_{w_1+1},\text{ }a_{h_1+1}+b_{w_1+2},\text{ }\cdots,\text{ }a_{h_1+1}+b_{w_2})\\ &\vdots\\ &\gcd(a_{h_2}+b_{w_1},\text{ }a_{h_2}+b_{w_1+1},\text{ }a_{h_2}+b_{w_1+2},\text{ }\cdots,\text{ }a_{h_2}+b_{w_2})\\ \end{aligned}
gcd(ah1+bw1, ah1+bw1+1, ah1+bw1+2, ⋯, ah1+bw2)gcd(ah1+1+bw1, ah1+1+bw1+1, ah1+1+bw1+2, ⋯, ah1+1+bw2)⋮gcd(ah2+bw1, ah2+bw1+1, ah2+bw1+2, ⋯, ah2+bw2)
更相减损法化简后:
gcd
(
a
h
1
+
b
w
1
,
b
w
1
+
1
−
b
w
1
,
b
w
1
+
2
−
b
w
1
+
1
,
b
w
1
+
3
−
b
w
1
+
2
,
⋯
,
b
w
2
−
b
w
2
−
1
)
gcd
(
a
h
1
+
1
+
b
w
1
,
b
w
1
+
1
−
b
w
1
,
b
w
1
+
2
−
b
w
1
+
1
,
b
w
1
+
3
−
b
w
1
+
2
,
⋯
,
b
w
2
−
b
w
2
−
1
)
⋮
gcd
(
a
h
2
+
b
w
1
,
b
w
1
+
1
−
b
w
1
,
b
w
1
+
2
−
b
w
1
+
1
,
b
w
1
+
3
−
b
w
1
+
2
,
⋯
,
b
w
2
−
b
w
2
−
1
)
\begin{aligned} &\gcd(a_{h_1}+b_{w_1},\text{ }b_{w_1+1}-b_{w_1},\text{ }b_{w_1+2}-b_{w_1+1},\text{ }b_{w_1+3}-b_{w_1+2},\text{ }\cdots,\text{ }b_{w_2}-b_{w_2-1})\\ &\gcd(a_{h_1+1}+b_{w_1},\text{ }b_{w_1+1}-b_{w_1},\text{ }b_{w_1+2}-b_{w_1+1},\text{ }b_{w_1+3}-b_{w_1+2},\text{ }\cdots,\text{ }b_{w_2}-b_{w_2-1})\\ &\vdots\\ &\gcd(a_{h_2}+b_{w_1},\text{ }b_{w_1+1}-b_{w_1},\text{ }b_{w_1+2}-b_{w_1+1},\text{ }b_{w_1+3}-b_{w_1+2},\text{ }\cdots,\text{ }b_{w_2}-b_{w_2-1})\\ \end{aligned}
gcd(ah1+bw1, bw1+1−bw1, bw1+2−bw1+1, bw1+3−bw1+2, ⋯, bw2−bw2−1)gcd(ah1+1+bw1, bw1+1−bw1, bw1+2−bw1+1, bw1+3−bw1+2, ⋯, bw2−bw2−1)⋮gcd(ah2+bw1, bw1+1−bw1, bw1+2−bw1+1, bw1+3−bw1+2, ⋯, bw2−bw2−1)
再进一步化简后:
gcd
(
a
h
1
+
b
w
1
,
b
w
1
+
1
−
b
w
1
,
b
w
1
+
2
−
b
w
1
+
1
,
b
w
1
+
3
−
b
w
1
+
2
,
⋯
,
b
w
2
−
b
w
2
−
1
)
gcd
(
a
h
1
+
b
w
1
,
a
h
1
+
1
−
a
h
1
,
a
h
1
+
2
−
a
h
1
+
1
,
a
h
1
+
3
−
a
h
1
+
2
,
⋯
,
a
h
2
−
a
h
2
−
1
)
\begin{aligned} \gcd(a_{h_1}+b_{w_1},\text{ }b_{w_1+1}-b_{w_1},\text{ }b_{w_1+2}-b_{w_1+1},\text{ }b_{w_1+3}-b_{w_1+2},\text{ }\cdots,\text{ }b_{w_2}-b_{w_2-1})\\ \gcd(a_{h_1}+b_{w_1},\text{ }a_{h_1+1}-a_{h_1},\text{ }a_{h_1+2}-a_{h_1+1},\text{ }a_{h_1+3}-a_{h_1+2},\text{ }\cdots,\text{ }a_{h_2}-a_{h_2-1})\\ \end{aligned}
gcd(ah1+bw1, bw1+1−bw1, bw1+2−bw1+1, bw1+3−bw1+2, ⋯, bw2−bw2−1)gcd(ah1+bw1, ah1+1−ah1, ah1+2−ah1+1, ah1+3−ah1+2, ⋯, ah2−ah2−1)
最后简单结合:
gcd
(
a
h
1
+
b
w
1
,
gcd
i
=
h
1
+
1
h
2
(
a
i
−
a
i
−
1
)
,
gcd
j
=
w
1
+
1
w
2
(
b
j
−
b
j
−
1
)
)
\begin{aligned} \gcd(a_{h_1}+b_{w_1},\text{ }\gcd_{i=h_1+1}^{h_2}(a_i-a_{i-1}),\text{ }\gcd_{j=w_1+1}^{w_2}(b_j-b_{j-1}))\\ \end{aligned}
gcd(ah1+bw1, i=h1+1gcdh2(ai−ai−1), j=w1+1gcdw2(bj−bj−1))
我们现在就得到了一个简单明了的式子了。而这个式子由于与区间有关,所以我们就可以考虑用经常解决区间问题的 线段树 来进行区间查询,当然因为此题没有区间修改,就也可以用 ST表 来操作。我这里是用线段树做的。
Code:
#include<bits/stdc++.h>
#define ri register int
#define rll register long long
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int INF=0x3f3f3f3f;
const int N=2e5+10;
int n,T;
int a[N],b[N];
inline int gcd__(int a, int b){// 最快GCD的求法
if(!a) return b;
if(!b) return a;
int az=__builtin_ctz(a), bz=__builtin_ctz(b),z=(az>bz?bz:az), diff;
b>>=bz;
while(a){
a>>=az;
diff=b-a;
az=__builtin_ctz(diff);
if(a<b) b=a;
a=(diff<0?-diff:diff);
}
return b<<z;
}
namespace SegmentTree{
int a[N]={0};
struct SG{
struct node{
int l,r;ll gcd;
#define l(x) tree[x].l
#define r(x) tree[x].r
#define gcd(x) tree[x].gcd
}tree[N<<2];
void build(int p,int l,int r){
l(p)=l, r(p)=r;
if(l==r){ gcd(p)=(a[l]>=0? a[l]: -a[l]); return;}
int mid=(l+r)>>1;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
gcd(p)=gcd__(gcd(p*2),gcd(p*2+1));
}
ll ask_gcd(int p,int l,int r){
if(l<=l(p)&&r(p)<=r) return gcd(p);
int mid=(l(p)+r(p))>>1;
ll d=0;
if(l<=mid) d=gcd__(d,ask_gcd(p*2,l,r));
if(r>mid) d=gcd__(d,ask_gcd(p*2+1,l,r));
return d;
}
}tr1,tr2;
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>n>>T;
for(ri i=1;i<=n;i++) cin>>a[i], SegmentTree::a[i]=a[i]-a[i-1];
SegmentTree::tr1.build(1,1,n);
for(ri i=1;i<=n;i++) cin>>b[i], SegmentTree::a[i]=b[i]-b[i-1];
SegmentTree::tr2.build(1,1,n);
// 重定义一下变量名,防止与std中的变量名冲突
#define x1 yinqyx1
#define y1 yinqyy1
#define x2 yinqyx2
#define y2 yinqyy2
int x1,x2,y1,y2,gcda,gcdb,ans;
while(T--){
cin>>x1>>x2>>y1>>y2;
gcda=SegmentTree::tr1.ask_gcd(1,x1+1,x2);
gcdb=SegmentTree::tr2.ask_gcd(1,y1+1,y2);
ans=gcd__(gcda,gcdb), ans=gcd__(ans,a[x1]+b[y1]);
cout<<ans<<'\n';
}
return 0;
}