CF1609F Interesting Sections 题解

分治,设当前区间为 $[l,r]$,考虑跨过分治中点 $m=\left\lfloor\dfrac{l+r}2\right\rfloor$ 的满足条件的区间个数。

枚举区间左端点 $i\in[l,m]$,设右端点为 $j$,则对每个 $i$,总有 $p1,p2$ 满足:

  • $\forall j\in(m,p1]$,$[i,j]$ 的 $\max,\min$ 均落在 $[i,m]$ 中,

则若此时 $\text{popcount}(\max\limits_{k=i}^ma_k)=\text{popcount}(\min\limits_{k=i}^ma_k)$,则所有 $j\in(m,p1]$ 的 $[i,j]$ 均符合要求,否则均不负责要求。

  • $\forall j\in(p1,p2]$,$[i,j]$ 的 $\max,\min$ 一个落在 $[i,m]$ 中,一个落在 $(m,j]$ 中,

以 $\min$ 落在 $[i,m]$ 中,$\max$ 落在 $(m,j]$ 中为例,

问题变为统计 $(p1,p2]$ 中有多少 $j$ 满足 $\text{popcount}(\max\limits_{k=m+1}^ja_k)=\text{popcount}(\min\limits_{k=i}^ma_k)$,

直接开桶维护 $c_x$ 表示当前 $(p1,p2]$ 中有多少 $j$ 满足 $\text{popcount}(\max\limits_{k=m+1}^ja_k)=x$,更新 $p1,p2$ 时更新这个桶即可。

  • $\forall j\in(p2,r]$,$[i,j]$ 的 $\max,\min$ 均落在 $(m,j]$ 中,

问题变为统计 $(p2,r]$ 中有多少 $j$ 满足 $\text{popcount}(\max\limits_{k=m+1}^ja_k)=\text{popcount}(\min\limits_{k=m+1}^ja_k)$,

发现与 $i$ 无关,提前预处理 $e_x$ 表示 $(m,x]$ 中满足该条件的 $j$ 的个数。

然后倒序枚举 $i$,发现 $p1,p2$ 单调后移,双指针即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define int long long
using namespace std;
int n, q, a[1000050], e[1000050], c1[70], c2[70];
void F(int l, int r)
{
    if (l == r)
        return void(++q);
    int m = l + r >> 1;
    memset(c1, 0, sizeof c1);
    memset(c2, 0, sizeof c2);
    e[m] = 0;
    long long u = 1e18, v = -1e18, u1 = 1e18, v1 = -1e18, u2 = 1e18, v2 = -1e18;
    for (int i = m + 1; i <= r; ++i)
        e[i] = e[i - 1] + (__builtin_popcountll(u = min(u, a[i])) == __builtin_popcountll(v = max(v, a[i])));
    u = 1e18;
    v = -1e18;
    for (int i = m, p1 = m, p2 = m; i >= l; --i)
    {
        u = min(u, a[i]);
        v = max(v, a[i]);
        while (p1 < r && u <= min(u1, a[p1 + 1]) && v >= max(v1, a[p1 + 1]))
            u1 = min(u1, a[++p1]), v1 = max(v1, a[p1]), --c1[__builtin_popcountll(u1)], --c2[__builtin_popcountll(v1)];
        while (p2 < r && (u <= min(u2, a[p2 + 1]) || v >= max(v2, a[p2 + 1])))
            u2 = min(u2, a[++p2]), v2 = max(v2, a[p2]), ++c1[__builtin_popcountll(u2)], ++c2[__builtin_popcountll(v2)];
        if (__builtin_popcountll(u) == __builtin_popcountll(v))
            q += p1 - m;
        q += e[r] - e[p2];
        if (u <= u2)
            q += c2[__builtin_popcountll(u)];
        else
            q += c1[__builtin_popcountll(v)];
    }
    F(l, m);
    F(m + 1, r);
}
signed main()
{
    scanf("%lld", &n);
    for (int i = 1; i <= n; ++i)
        scanf("%lld", a + i);
    F(1, n);
    printf("%lld", q);
    return 0;
}
posted @ 2023-12-20 20:29  5k_sync_closer  阅读(3)  评论(0编辑  收藏  举报  来源