ABC254F 题解

前言

题目传送门!

更好的阅读体验?

这题 trick 就是更相减损术:\(\gcd\{a_1, a_2, a_3, \cdots, a_n\} = \gcd\{a_1, a_2 - a_1, a_3 - a_2, \cdots, a_n - a_{n-1}\}\)

思路

有了这个 trick 之后这题就好做了。并不需要其他题解一样画表格,化简式子就行,过程并没有难点。

\[\begin{aligned} \text{answer} & = \gcd\limits_{i=x1}^{x2}\Big(\normalsize\gcd\limits_{j=y_1}^{y_2} (a_i + b_j)\Big)\normalsize \\ & = \gcd\limits_{i=x1}^{x2}\Big(\gcd\{ a_i + b_{y_1}, a_i + b_{y_1+1}, a_i + b_{y_1+2}, \cdots, a_i + b_{y_2}\}\Big)\normalsize \\ & = \gcd\limits_{i=x1}^{x2}\Big(\gcd\{ a_i + b_{y_1}, \color{red}b_{y_1+1}-b_{y_1}, b_{y_1+2}-b_{y_1+1}, \cdots, b_{y_2}-b_{y_2-1}\color{black}\}\Big)\normalsize \\ & = \gcd\Big(\normalsize\color{red}b_{y_1+1}-b_{y_1}, b_{y_1+2}-b_{y_1+1}, \cdots, b_{y_2}-b_{y_2-1}\color{black}, \color{blue}\gcd\limits_{i=x_1}^{x_2}(a_i+b_{y_1})\color{black} \Big)\normalsize \\ & = \gcd\Big(\normalsize\color{red}\gcd\limits_{j=y_1+1}^{y_2} (b_j-b_{j-1})\color{black}, \color{blue}\gcd\{a_{x_1}+b_{y_1}, a_{y_1+1}-a_{y_1}, \cdots, a_{y_2}-a_{y_2-1}\} \color{black}\Big)\normalsize \\ & = \gcd\Big(\normalsize\color{red}\gcd\limits_{j=y_1+1}^{y_2} (b_j-b_{j-1})\color{black}, \color{blue}a_{x1}+b_{y1}, \gcd\limits_{i=x1+1}^{x2}(a_i-a_{i-1})\color{black}\Big)\normalsize \\ & = \gcd\Big(\normalsize a_{x1}+b_{y1}, \gcd\limits_{i=x1+1}^{x2}(a_i-a_{i-1}), \gcd\limits_{i=y_1+1}^{y_2} (b_i-b_{i-1})\Big)\normalsize \\ \end{aligned} \]

综上,只需维护两个 DS,分别支持求 \((a_i - a_{i-1})\)\((b_i - b_{i-1})\) 的区间 gcd。掏一手 ST 表拿下。

代码

#include <iostream>
#include <cstdio>
#include <cmath>
#define y1 zltAKIOI
using namespace std;
const int N = 2e5 + 5;
int n, q;
int gcd(int x, int y) {return y == 0 ? x : gcd(y, x % y);}
struct ST {
	int gc[N][20];
	void build(int a[])
	{
		for (int i = 1; i <= n; i++) gc[i][0] = abs(a[i] - a[i - 1]);
		for (int j = 1; j <= 18; j++)
			for (int i = 1; i + (1 << j) - 1 <= n; i++)
				gc[i][j] = gcd(gc[i][j - 1], gc[i + (1 << (j - 1))][j - 1]);
	}
	int query(int l, int r)
	{
		if (l > r) return 0;
		int len = log2(r - l + 1);
		return gcd(gc[l][len], gc[r - (1 << len) + 1][len]);
	}
} A, B;
int a[N], b[N];
int main()
{
	scanf("%d%d", &n, &q);
	for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
	for (int i = 1; i <= n; i++) scanf("%d", &b[i]);
	A.build(a), B.build(b);
	while (q--)
	{
		int x1, x2, y1, y2;
		scanf("%d%d%d%d", &x1, &x2, &y1, &y2);
		printf("%d\n", gcd(gcd(A.query(x1 + 1, x2), B.query(y1 + 1, y2)), a[x1] + b[y1]));
	}
	return 0;
}

希望能帮助到大家!

posted @ 2023-05-14 09:56  liangbowen  阅读(10)  评论(0编辑  收藏  举报