惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

爱范儿
爱范儿
WordPress大学
WordPress大学
C
Check Point Blog
GbyAI
GbyAI
U
Unit 42
Google DeepMind News
Google DeepMind News
B
Blog RSS Feed
Blog — PlanetScale
Blog — PlanetScale
J
Java Code Geeks
I
InfoQ
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Hugging Face - Blog
Hugging Face - Blog
Vercel News
Vercel News
博客园 - 【当耐特】
美团技术团队
小众软件
小众软件
S
SegmentFault 最新的问题
Jina AI
Jina AI
阮一峰的网络日志
阮一峰的网络日志
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
The Cloudflare Blog
Last Week in AI
Last Week in AI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
Visual Studio Blog

博客园_首页

Plist 二进制格式 Milvus 和 PGVector,哪个更好? OpenClaw 已过时?在 VS Code 中运行 Hermes Agent! 第30篇文章:一个大三计科生的自白 Manim如何在数学公式中完美显示中文? Docker 部署 RocketMQ 5 并发编程核心概念辨析 C#事务处理最佳实践:别再让“主表存了、明细丢了”的破事发生 CLI 是什么?为什么大厂突然集体卷命令行? 【从0到1构建一个ClaudeAgent】协作-自主Agent UIImageView 设置图片不生效的原因排查 最小二乘问题详解20:无先验约束下的增量式SFM自由网平差 痞子衡嵌入式:大话双核i.MXRT1180之XIP应用里借助MU实现可靠Flash IAP的方法 AI Chat 封装, SemanticKerne.AiProvider.Unified 已发布 Windows下右键编辑js文件无法打开记事本——在注册表中使用环境变量 在后台服务中使用 Scoped 服务,为什么总是报错? H200 安装驱动并使用sglang启动模型 wireshark 抓包Trap上报告警内容 我用 AI 辅助开发了一系列小工具(2):图片压缩工具 [A Primer On MC and CC] 2.1 Memory Consistency 1 - 指令重排序和 SC 模型 Oracle数据库SCN推进技术详解与实践指南 玩转控件:封装个带图片的Label控件 Claude Code 4.7 真正该升级的不是模型,而是你的工作流 前端小白一句话,AI 帮我做了个颜值拉满的桌面媒体播放器。当代码不再是门槛,一句话编程就是现实。 5. WorkBuddy: 小龙虾的灵魂三件套,让你的小龙虾不只是工具 SQLite 分片方案实战:三种分片策略的深度对比 告别简陋 UI!一款基于 Fluent Design 和基于 WinUI 的开源免费、现代化的 Avalonia UI 控件库 关于二进制排列组合枚举的总结 AI开发-python-LangGraph框架(3-27-LangGraph从零实现大模型智能决策工作流) ElasticSearch主分片和副本分片概念详解
邪修卡常:动态bitset
GroundhogKin · 2026-04-25 · via 博客园_首页

前言

由于 std::bitset 仅支持编译期固定大小,无法动态确定长度,这使得某些 \(\sum n \leq N\) 的多测题中使用 std::bitset 超时。于是我让 AI 生成了一份比赛中可用的动态bitset模版,并且测试了其在部分板题里的性能。

实现

#include <iostream>
#include <vector>
#include <cstdint>
using namespace std;

using u64 = uint64_t;

struct dynamic_bitset
{
    int n;
    std::vector<u64> b;

    dynamic_bitset(int _n = 0) : n(_n), b((_n + 63) >> 6, 0) {}

    void resize(int new_n) {
        if (new_n == n) return;
        b.resize((new_n + 63) >> 6, 0);   // 新块自动置零
        n = new_n;
        clean_tail();
    }

    // 读取某一位(只读,不抛异常)
    bool operator[](int pos) const {
        return (b[pos >> 6] >> (pos & 63)) & 1;
    }

    // 设置某一位
    void set(int pos, bool val = true) {
        if (val)
            b[pos >> 6] |= 1ULL << (pos & 63);
        else
            b[pos >> 6] &= ~(1ULL << (pos & 63));
    }

    // 置零某一位
    void reset(int pos) {
        b[pos >> 6] &= ~(1ULL << (pos & 63));
    }

    // 翻转某一位
    void flip(int pos) {
        b[pos >> 6] ^= 1ULL << (pos & 63);
    }

    // 位运算
    dynamic_bitset& operator&=(const dynamic_bitset& rhs) {
        for (size_t i = 0; i < b.size(); ++i) b[i] &= rhs.b[i];
        return *this;
    }
    dynamic_bitset& operator|=(const dynamic_bitset& rhs) {
        for (size_t i = 0; i < b.size(); ++i) b[i] |= rhs.b[i];
        return *this;
    }
    dynamic_bitset& operator^=(const dynamic_bitset& rhs) {
        for (size_t i = 0; i < b.size(); ++i) b[i] ^= rhs.b[i];
        return *this;
    }
    dynamic_bitset operator~() const {
        dynamic_bitset res = *this;
        for (auto& x : res.b) x = ~x;
        res.clean_tail();
        return res;
    }

    // 1 的个数
    int count() const {
        int ans = 0;
        for (auto x : b) ans += __builtin_popcountll(x);
        return ans;
    }

    // 清除尾部多余位
    void clean_tail() {
        if (n == 0) return;
        int rem = n & 63;
        if (rem) b.back() &= (1ULL << rem) - 1;
    }
};

// 非成员二元运算符(方便书写)
inline dynamic_bitset operator&(dynamic_bitset a, const dynamic_bitset& b) { return a &= b; }
inline dynamic_bitset operator|(dynamic_bitset a, const dynamic_bitset& b) { return a |= b; }
inline dynamic_bitset operator^(dynamic_bitset a, const dynamic_bitset& b) { return a ^= b; }

使用范例

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    dynamic_bitset a(10),b;
    b.resize(10);

    a.set(1), a.set(2);
    b.flip(0);

    dynamic_bitset c(a|b);
    cout << c.count() << endl;

    return 0;
}

与 std::bitset 的区别

  • 不支持左移/右移
  • []只读,无法通过 bit[0] = 1 来置位。置位只能使用 set 和 reset 函数
  • 不支持 any、all 等函数(这些也没什么必要)
  • 输出不与 cout 兼容,只能逐位遍历
  • 不支持转化整数和字符串

与 std::bitset 的性能对比

【模板】传递闭包

std::bitset

image

动态bitset

image

[PA 2025] 集合 1 / Zbiory 1

std::bitset

image

动态bitset

image

可以看到与 std::bitset 的性能差距还是比较明显。但是作为一种走投无路下的卡常手段,动态bitset已经足够了。如果再追求优化,可以考虑上 SIMD 指令集,由于比赛中不确定是否能够使用,这里不太推荐。