[ABC254F] Rectangle GCD 题解
[ABC254F] Rectangle GCD Solution
更好的阅读体验戳此进入
题面
给定序列 $ a_n, b_n $,存在 $ n \times n $ 的网格图,令图上 $ (i, j) $ 位置的值为 $ a_i + b_j \(。\) q $ 次询问给定 $ h_1, h_2, w_1, w_2 $,查询左上角为 $ (h_1, w_1) $,右下角为 $ (h_2, w_2) $ 的矩形中所有数的 $ \gcd $。
Solution
挺好的一道水题,有一道类似的题,AcWing 246 区间最大公约数,简而言之就是实现区间加,区间求 $ \gcd $。这道题也是类似的。
首先有一个性质,更相减损术,即 $ \gcd(a, b) = \gcd(a, b - a) $。然后我们尝试列举一个以 $ (i, j) $ 为左上角,$ (x, y) $ 为右下角的矩形:
| $ a_{i} + b_{j} $ | $ a_{i} + b_{j + 1} $ | $ a_{i} + b_{j + 2} $ | $ \cdots $ | $ a_{i} + b_{y} $ |
|---|---|---|---|---|
| $ a_{i + 1} + b_{j} $ | $ a_{i + 1} + b_{j + 1} $ | $ a_{i + 1} + b_{j + 2} $ | $ \cdots $ | $ a_{i + 1} + b_{y} $ |
| $ a_{i + 2} + b_{j} $ | $ a_{i + 2} + b_{j + 1} $ | $ a_{i + 2} + b_{j + 2} $ | $ \cdots $ | $ a_{i + 2} + b_{y} $ |
| $ \cdots $ | $ \cdots $ | $ \cdots $ | $ \cdots $ | $ \cdots $ |
| $ a_{x} + b_{j} $ | $ a_{x} + b_{j + 1} $ | $ a_{x} + b_{j + 2} $ | $ \cdots $ | $ a_{x} + b_{y} $ |
然后不难发现可以通过更相减损术,对这个矩形横向进行差分:
| $ a_{i} + b_{j} $ | $ b_{j + 1} - b_j $ | $ b_{j + 2} - b_{j + 1} $ | $ \cdots $ | $ b_{y} - b_{y - 1} $ |
|---|---|---|---|---|
| $ a_{i + 1} + b_{j} $ | $ b_{j + 1} - b_j $ | $ b_{j + 2} - b_{j + 1} $ | $ \cdots $ | $ b_{y} - b_{y - 1} $ |
| $ a_{i + 2} + b_{j} $ | $ b_{j + 1} - b_j $ | $ b_{j + 2} - b_{j + 1} $ | $ \cdots $ | $ b_{y} - b_{y - 1} $ |
| $ \cdots $ | $ \cdots $ | $ \cdots $ | $ \cdots $ | $ \cdots $ |
| $ a_{x} + b_{j} $ | $ b_{j + 1} - b_j $ | $ b_{j + 2} - b_{j + 1} $ | $ \cdots $ | $ b_{y} - b_{y - 1} $ |
发现除了最初始的位置,剩下的每一列都是相同的,所以我们不难想到,除了第一行第一列之外的数,会因为重复所以可以不用考虑。同时对于对应的第一列,也可以差分。最后就可以变成,对于一段查询,求的是序列 $ a $ 差分数组的 $ [w_1 + 1, w_2] $ 的 $ \gcd $,和序列 $ b $ 差分数组的 $ [h_1 + 1, h_2] $ 的 $ \gcd $,再和 $ a_{h_1} + b_{w_1} $ 做一下 $ \gcd $ 即可,记得判断 $ w_1 \neq w_2 $ 和 $ h_1 \neq h_2 $。
然后考虑如何快速维护区间的 $ \gcd $,这个东西也就可以直接挂在线段树上,或者因为没有修改,用 ST表 也行(不过我不喜欢 ST表,所以用的线段树维护)。
Code
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}
using namespace std;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
#define MAXN (210000)
template < typename T = int >
inline T read(void);
int N, Q;
int A[MAXN], B[MAXN], dA[MAXN], dB[MAXN];
class SegTree{
private:
int tr[MAXN << 2];
#define LS (p << 1)
#define RS (LS | 1)
#define MID ((gl + gr) >> 1)
public:
void Pushup(int p){tr[p] = __gcd(tr[LS], tr[RS]);}
void Build(bool flag, int p = 1, int gl = 1, int gr = N){//true - line(y), false - row(x)
if(gl == gr)return tr[p] = flag ? dB[gl] : dA[gl], void();
Build(flag, LS, gl, MID), Build(flag, RS, MID + 1, gr);
Pushup(p);
}
int Query(int l, int r, int p = 1, int gl = 1, int gr = N){
if(l <= gl && gr <= r)return tr[p];
if(r <= MID)return Query(l, r, LS, gl, MID);
if(l >= MID + 1)return Query(l, r, RS, MID + 1, gr);
return __gcd(Query(l, r, LS, gl, MID), Query(l, r, RS, MID + 1, gr));
}
}stLine, stRow;
int main(){
N = read(), Q = read();
for(int i = 1; i <= N; ++i)A[i] = read(), dA[i] = A[i] - A[i - 1];
for(int i = 1; i <= N; ++i)B[i] = read(), dB[i] = B[i] - B[i - 1];
stLine.Build(true), stRow.Build(false);
while(Q--){
int h1 = read(), h2 = read(), w1 = read(), w2 = read();
int ans = A[h1] + B[w1];
if(w1 != w2)ans = __gcd(ans, stLine.Query(w1 + 1, w2));
if(h1 != h2)ans = __gcd(ans, stRow.Query(h1 + 1, h2));
printf("%d\n", abs(ans));
}
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
int flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
UPD
update-2022_12_06 初稿

浙公网安备 33010602011771号