CF2006C Eri and Expanded Sets
题解区怎么都要数据结构??这篇题解主要讲解本题的一个维护技巧。
假如我们知道了这个问题的结论,现在我们关心的是怎么求关于 \(\gcd\) 带来的贡献。
考虑从左往右扫描右端点,我们来试着维护每个左端点的信息。我们固定 \(r\),并设 \([l,r]\) 区间的 \(\gcd\) 为 \(g(l)\),不难发现 \(g(l)|g(l+1)\),并且一个经典结论是一个 \(\gcd\) 的结果顶多只会被修改 \(\log\) 次。
于是 \(|a_r-a_{r-1}|\) 修改的 \(g(l)\) 是一段后缀,我们直接暴力修改即可,直到没有发生改变为止。修改时维护 \(l\) 是否为好的区间,当前以 \(r\) 为右端点的好的区间数量是容易维护的,代码很短,时间复杂度 \(\mathcal{O}(n\log^2V)\),常数巨小。
代码:
int n, a[N];
bool ok[N];
int val[N];
void solve () {
n = rd ();
rep (i, 1, n) a[i] = rd ();
int cnt (0), ans (0);
rep (i, 1, n) val[i] = ok[i] = 0;
rep (i, 1, n) {
++ ans;
int j (i);
while (j > 1) {
int las = val[j];
val[j] = __gcd (val[j], abs (a[i] - a[i - 1]));
if (val[j] == (val[j] & -val[j])) {
if (! ok[j]) ++ cnt, ok[j] = 1;
} else if (ok[j]) -- cnt, ok[j] = 0;
if (val[j] == las) break;
-- j;
}
ans += cnt;
}
printf ("%lld\n", ans);
}

浙公网安备 33010602011771号