题意:
给定等长的正整数组 \(a[],b[]\),它们确定了一个矩阵 \(A_{i,j} = a_i+b_j\)。\(q\) 次询问,回答矩阵中一个矩形区域内所有数的 \(\gcd\)
\(n,q\le 2e5\)
思路:
差分,绝对值,st表区间 gcd
\(\gcd(a_1, a_2, a_3, \cdots ) = \gcd(a_1, a_2-a_1, a_3-a_2, \cdots )\)
写代码注意套个绝对值
证明:
\(\gcd(x,y) = \gcd (x-y, y), x>y\) 对大小有要求,不妨换条路走
若 \(g|a,g|b\) 则 \(g|a+b, g|abs(a-b)\),所以等式两边的因数相同
题解见 https://zhuanlan.zhihu.com/p/524503584
const signed N = 3e5 + 5;
int n, q, a[N], b[N];
int logn[N], f[N][19], g[N][19];
void initlog() {
logn[1] = 0, logn[2] = 1;
for(int i = 3; i < N; i++)
logn[i] = logn[i >> 1] + 1;
}
void pre(int f[N][19]) {
for(int j = 1; j < 19; j++)
for(int i = 1; i + (1 << j) - 1 <= n; i++)
f[i][j] = __gcd(f[i][j - 1], f[i+(1<<(j-1))][j - 1]);
}
int ask(int f[N][19], int l, int r) {
if(l > r) return 0;
int k = logn[r - l + 1];
return __gcd(f[l][k], f[r+1-(1<<k)][k]);
}
void sol() {
initlog(); //预处理log2
cin >> n >> q;
for(int i = 1; i <= n; i++)
cin >> a[i], f[i][0] = abs(a[i] - a[i - 1]);
for(int i = 1; i <= n; i++)
cin >> b[i], g[i][0] = abs(b[i] - b[i - 1]);
pre(f), pre(g);
while(q--) {
int h1, h2, w1, w2;
cin >> h1 >> h2 >> w1 >> w2;
int ans = __gcd(ask(f, h1 + 1, h2), ask(g, w1 + 1, w2));
cout << __gcd(ans, a[h1] + b[w1]) << '\n';
}
}
标签:pre,GCD,int,19,w1,logn,abc254,Rectangle,gcd
From: https://www.cnblogs.com/wushansinger/p/17047295.html