给定一个长度为 nn 的序列 aia_i。若 ai=ai1+ai+12a_i = \frac{a_{i-1}+a_{i+1}}{2},则可以删除 aia_i,后面的数依次向前填充,求最少剩下多少数。

先差分。令 di=aiai1d_i = a_i - a_{i-1},则 ai=ai1+ai+12a_i = \frac{a_{i-1}+a{i+1}}{2} 等同于 di=di+1d_i = d_{i+1},删除也就是把 did_idjd_j 合并,即翻倍。

did_i 只能不断翻倍,故若 dilowbit(di)djlowbit(dj)\frac{d_i}{\mathrm{lowbit}(d_i)} \neq \frac{d_j}{\mathrm{lowbit}(d_j)},则 did_idjd_j 一定不能合并(di=0d_i=0 特殊讨论)。可以按照 dilowbit(di)\frac{d_i}{\mathrm{lowbit}(d_i)}dd 数组划分。

定义 pre(i)=dilowbit(di)pre(i) = \frac{d_i}{\mathrm{lowbit}(d_i)},定义 f(i)f(i) 表示前 ii 个最多合并个数,g(i,j)g(i, j) 表示以 ii 为右端点,合并出 pre(i)×2jpre(i) \times 2^j 的左端点,用类似倍增的方法转移 gg,通过 gg 转移 ff

constexpr unsigned long long lowbit(unsigned long long x) { return x & -x; }
constexpr unsigned long long getexp(unsigned long long x) { return std::popcount(lowbit(x) - 1); }

void solve()
{
    int n;
    scanf("%d", &n);
    std::vector<int> a(n);
    for (auto &i : a) scanf("%d", &i);
    std::vector<long long> da(n);
    for (int i = 1; i < n; i++) da[i] = (long long)a[i] - a[i - 1];

    int ans = n;
    {
        int i = 1;
        while (i < n) {
            int j = i + 1;
            if (da[i] == 0) {
                while (j < n && da[j] == 0) j++;
                ans -= j - i - 1;
            } else {
                auto pre = da[i] / (signed)lowbit(std::abs(da[i]));
                while (j < n && da[j] != 0 && da[j] / (signed)lowbit(std::abs(da[j])) == pre) j++;
                std::vector<int> f(j - i);
                std::vector<std::vector<int>> g(j - i, std::vector<int>(32, -1));
                for (int p = 0; p < j - i; p++) {
                    int mink = getexp(std::abs(da[p + i]));
                    g[p][mink] = p;
                    if (p > 0) f[p] = f[p - 1];
                    for (int k = mink + 1; k < 32; k++) {
                        if (g[p][k - 1] - 1 >= 0 && g[g[p][k - 1] - 1][k - 1] >= 0) {
                            g[p][k] = g[g[p][k - 1] - 1][k - 1];
                            if (g[p][k] > 0) f[p] = std::max(f[p], f[g[p][k] - 1] + (p - g[p][k]));
                            else f[p] = std::max(f[p], p - g[p][k]);
                        }
                    }
                }
                ans -= f.back();
            }
            i = j;
        }
    }
    printf("%d\n", ans);
}

代码时注意处理负数、0 的情况。