题目
题意:
给你两个数组
A
,
B
A,B
A,B
生成一个矩阵:位置
(
i
,
j
)
(i,j)
(i,j)的值为
A
i
+
B
j
A_i+B_j
Ai+Bj
询问q次,每次询问一个子矩阵的gcd。
思路:
step1:
弱化下问题:假如是询问q次区间gcd?
那么我们可以考虑用线段树优化或者rmq。
step2:
- 先看一行的计算结果:
g c d ( A x 1 + B y 1 , A x 1 + B y 1 + 1 , . . . , A x 1 + B y 2 ) gcd(A_{x_1} + B_{y_1},A_{x_1} + B_{y_1+1},...,A_{x_1} + B_{y_2}) gcd(Ax1+By1,Ax1+By1+1,...,Ax1+By2)
根据差分,转换为
g c d ( A x 1 + B y 1 , B y 1 + 1 − B y 1 , . . . , B y 2 − B y 2 − 1 ) gcd(A_{x_1} + B_{y_1}, B_{y_1+1} - B_{y_1},..., B_{y_2} - B_{y_2-1}) gcd(Ax1+By1,By1+1−By1,...,By2−By2−1)
我们发现根据step1,我们可以快速计算出一行的结果。
- 看多行的结果:
g
c
d
(
A
x
1
+
B
y
1
,
A
x
1
+
B
y
1
+
1
,
.
.
.
,
A
x
1
+
B
y
2
)
gcd(A_{x_1} + B_{y_1},A_{x_1} + B_{y_1+1},...,A_{x_1} + B_{y_2})
gcd(Ax1+By1,Ax1+By1+1,...,Ax1+By2)
g
c
d
(
A
x
1
+
1
+
B
y
1
,
A
x
1
+
1
+
B
y
1
+
1
,
.
.
.
,
A
x
1
+
1
+
B
y
2
)
gcd(A_{x_1+1} + B_{y_1},A_{x_1+1} + B_{y_1+1},...,A_{x_1+1} + B_{y_2})
gcd(Ax1+1+By1,Ax1+1+By1+1,...,Ax1+1+By2)
…
g
c
d
(
A
x
2
+
B
y
1
,
A
x
2
+
B
y
1
+
1
,
.
.
.
,
A
x
2
+
B
y
2
)
gcd(A_{x_2} + B_{y_1},A_{x_2} + B_{y_1+1},...,A_{x_2} + B_{y_2})
gcd(Ax2+By1,Ax2+By1+1,...,Ax2+By2)
根据差分,转换为
g c d ( A x 1 + B y 1 , B y 1 + 1 − B y 1 , . . . , B y 2 − B y 2 − 1 ) gcd(A_{x_1} + B_{y_1}, B_{y_1+1} - B_{y_1},..., B_{y_2} - B_{y_2-1}) gcd(Ax1+By1,By1+1−By1,...,By2−By2−1)
g
c
d
(
A
x
1
+
1
+
B
y
1
,
B
y
1
+
1
−
B
y
1
,
.
.
.
,
B
y
2
−
B
y
2
−
1
)
gcd(A_{x_1 + 1} + B_{y_1}, B_{y_1+1} - B_{y_1},..., B_{y_2} - B_{y_2-1})
gcd(Ax1+1+By1,By1+1−By1,...,By2−By2−1)
…
g
c
d
(
A
x
2
+
B
y
1
,
B
y
1
+
1
−
B
y
1
,
.
.
.
,
B
y
2
−
B
y
2
−
1
)
gcd(A_{x_2} + B_{y_1}, B_{y_1+1} - B_{y_1},..., B_{y_2} - B_{y_2-1})
gcd(Ax2+By1,By1+1−By1,...,By2−By2−1)
我们会发现除了第一列以外,其他列的值一样,所以我们可以直接求出后面的gcd。
而第一列的gcd也可以快速根据step1维护。
step3:
板子的gcd可能会因为负数wa
AC
#include <iostream>
#include <cstdio>
#include <vector>
#include <map>
#include <unordered_map>
#include <set>
#include <algorithm>
#include <bits/stdc++.h>
#include <queue>
#include <stack>
#include <string>
#include <cmath>
#include <cstring>
#define For(i,x,y) for(int i = (x); i <= (y); i ++ )
#define fori(i,x,y) for(int i = (x); i < (y); i ++ )
#define sz(a) (int)a.size()
#define ALL(a) a.begin(), a.end()
#define mst(x,a) memset(x,a,sizeof(x))
#define pb push_back
#define eb emplace_back
#define mp make_pair
#define fi first
#define se second
#define db double
#define endl '\n'
#define debug(a) cout << #a << ": " << a << endl
using namespace std;
typedef long long LL;
typedef long long ll;
typedef unsigned long long ULL;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
typedef pair<int,int>pa;
typedef pair<ll,ll>pai;
typedef pair<db,db> pdd;
const db eps = 1e-6;
const db pi = acos(-1.0);
template<typename T1, typename T2> void ckmin(T1 &a, T2 b) { if (a > b) a = b; }
template<typename T1, typename T2> void ckmax(T1 &a, T2 b) { if (a < b) a = b; }
int read() {
int x = 0, f = 0; char ch = getchar();
while (!isdigit(ch)) f |= ch == '-', ch = getchar();
while (isdigit(ch)) x = 10 * x + ch - '0', ch = getchar();
return f ? -x : x;
}
template<typename T> void print(T x) {
if (x < 0) putchar('-'), x = -x;
if (x >= 10) print(x / 10);
putchar(x % 10 + '0');
}
template<typename T> void print(T x, char let) {
print(x), putchar(let);
}
template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }
const int maxn = 200000 + 6;
const int LOGMX = 20;
int gcd(int a, int b) {
if(b == 0) return a;
return gcd(b,a%b);
}
int a[maxn], b[maxn];
int c[maxn][LOGMX], d[maxn][LOGMX];
int logn[maxn];
void init(){
for(int i = 2; i < maxn; i ++ ) logn[i] = logn[i/2] + 1;
}
int query1(int l, int r) {
if(l > r) return 0;
int s = logn[r-l+1];
return std::gcd(c[l][s],c[r-(1<<s)+1][s]);
}
int query2(int l, int r) {
if(l > r) return 0;
int s = logn[r-l+1];
return std::gcd(d[l][s],d[r-(1<<s)+1][s]);
}
int main() {
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
// gcd(a1+b1,a1+b2,a1+b3);
// gcd(a1+b1,b2-b1,b3-b1)
init();
int n, q;
cin >> n >> q;
for(int i = 1; i <= n; i ++ ) cin >> a[i];
for(int i = 1; i <= n; i ++ ) cin >> b[i];
for(int i = 1; i < n; i ++ ) {
c[i][0] = a[i+1] - a[i];
d[i][0] = b[i+1] - b[i];
}
//rmq init
for(int j = 1; j < LOGMX; j ++ ) {
for(int i = 1; i + (1<<j) - 1 < n; i ++) {
c[i][j] = std::gcd(c[i][j-1], c[i+(1<<(j-1))][j-1]);
d[i][j] = std::gcd(d[i][j-1], d[i+(1<<(j-1))][j-1]);
}
}
for(int i = 1; i <= q; i ++ ) {
int x1,y1,x2,y2;
cin>> x1 >> x2 >> y1 >> y2;
cout << std::gcd(a[x1] + b[y1], gcd(query1(x1,x2-1), query2(y1,y2-1))) << endl;
}
return 0;
}
//负数的gcd,和推导