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;
}