CF2006C Eri and Expanded Sets

· · 题解

出题人题解。考虑一个集合 S 进行“扩展”操作后,得到的 S' 会是什么样子。

于是转化为了这样一个问题:求有多少区间的 \gcd 形如 2^k0。对于固定的左端点,区间 \gcd 形如 2^kr 是一段后缀;而形如 0 的是一段 l 开头后缀的前缀。

因为端点有单调性,貌似可以使用 baka's trick 做到比较好看的复杂度,但是我比较蠢,写了个二分 ST 表,两只 \log,也可以通过。

int query(int l, int r) {
    int d = __lg(r - l + 1);
    return __gcd(st[d][l], st[d][r - (1 << d) + 1]);
} 

bool check(int x) {
    return x && (x & -x) == x;
}

void fake_main() {
    n = read(), ans = n;
    rep(i, 1, n) a[i] = read();
    rep(i, 1, n - 1) st[0][i] = b[i] = abs(a[i] - a[i + 1]);
    rep(d, 1, maxd - 1) rep(i, 1, n - (1 << d)) st[d][i] = __gcd(st[d - 1][i], st[d - 1][i + (1 << d - 1)]);
    rep(i, 1, n - 1) {
        if (check(query(i, n - 1))) {
            int l = i, r = n - 1;
            while (l < r) {
                int mid = l + r >> 1;
                if (check(query(i, mid))) r = mid;
                else l = mid + 1;
            }
            ans += n - l;
        }
        if (!b[i]) {
            int l = i, r = n - 1;
            while (l < r) {
                int mid = l + r + 1 >> 1; 
                if (!query(i, mid)) l = mid;
                else r = mid - 1;
            }
            ans += l - i + 1;
        }
    }
    write(ans), pc('\n'); 
}