原題:D - Integers Have Friends
題意:
給定一個數組,求一個最長子數組滿足\(a_i \,\, mod \,\, m \,\, = \,\, a_{i + 1} \,\, mod \,\, m = ... \,\, = \,\, a_j \,\,mod\,\, m \,\,(m \geq 2)\)
求其最長長度。
根據同余定理:\(a≡b\,(mod \,\,m)\)等價於\(a - b\)可以被\(m\)整除。那么還有\(b[i] = a[i + 1] - a[i]\),所以說如果一個子數組同余於\(m\),那么這個子數組的差分數組一定可以被\(m\)整除,那么就說明這個子數組有一個最大公約數\(m\),所以我們可用線段樹或者\(st\)表來維護一下區間的\(gcd\),那么對於求一個區間最大長度用雙指針維護即可。
代碼
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2E5 + 10, M = 20;
LL a[N], b[N];
int n;
LL f[N][M];
int l2g[N];
void init() {
for (int j = 0; j < M; j++) {
for (int i = 1; i + (1 << j) - 1 <= n; i++) {
if (!j) f[i][j] = b[i];
else f[i][j] = __gcd(f[i][j - 1], f[i + (1 << j - 1)][j - 1]);
}
}
}
LL query(int l, int r) {
int k = l2g[r - l + 1];
return __gcd(f[l][k], f[r - (1 << k) + 1][k]);
}
int main() {
int t; scanf("%d", &t);
l2g[2] = 1;
for (int i = 3; i <= N; i++) l2g[i] = l2g[i / 2] + 1;
while (t--) {
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
for (int i = 1; i <= n - 1; i++) b[i] = abs(a[i] - a[i + 1]);
if (n == 1) {
cout << 1 << endl;
continue;
}
init();
int res = 0;
int j = 1;
for (int i = 1; i <= n - 1; i++) {
while (j <= i && query(j, i) == 1) j++;
res = max(res, i - j + 2);
}
printf("%d\n", res);
}
return 0;
}