CF1609F Interesting Sections 题解

分治,设当前区间为 [l,r],考虑跨过分治中点 m=l+r2 的满足条件的区间个数。

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

  • j(m,p1][i,j]max,min 均落在 [i,m] 中,

则若此时 popcount(maxk=imak)=popcount(mink=imak),则所有 j(m,p1][i,j] 均符合要求,否则均不负责要求。

  • j(p1,p2][i,j]max,min 一个落在 [i,m] 中,一个落在 (m,j] 中,

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

问题变为统计 (p1,p2] 中有多少 j 满足 popcount(maxk=m+1jak)=popcount(mink=imak)

直接开桶维护 cx 表示当前 (p1,p2] 中有多少 j 满足 popcount(maxk=m+1jak)=x,更新 p1,p2 时更新这个桶即可。

  • j(p2,r][i,j]max,min 均落在 (m,j] 中,

问题变为统计 (p2,r] 中有多少 j 满足 popcount(maxk=m+1jak)=popcount(mink=m+1jak)

发现与 i 无关,提前预处理 ex 表示 (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 @   Jijidawang  阅读(6)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示