“[GESP202509 五级] 有趣的数字和”分块做法

news/2025/10/15 1:27:41/文章来源:https://www.cnblogs.com/03Goose/p/19142131

这个题看到第一眼不是暴力数位 dp 创过去吗?
换以前,我虽然忘了数位 dp ,但是可能接着这个机会重新学一遍数位 dp 。
但是最近工作任务和学校任务都很重,根本不想重新学一遍数位 DP 。
反而让我发现了一个更通用更好更简单的做法。

洛谷链接:https://www.luogu.com.cn/problem/P14074

核心问题:问题容易被转化成计算 \(x \in [0, N]\) 中,所有满足 \(popcount(x)\) 是奇数的数字之和。
为了不引起人类语言上的歧义,形式化表示即要求计算:

\[\sum_{i = 0}^{N} [popcount(i) \bmod 2 = 1] \]

其中 [p]\(p\) 为真返回 \(1\) ,若 \(p\) 为假返回 \(0\)

关于 \(0 \sim N\) 内所有数在二进制下的加法贡献问题,常见的最无脑最简单方法是把指数折半。
根据经验,如果有 \(L(a^{x + y}) = L(a^{x}) \times L(a^{y})\) ,那么我们可以把 \(O(a^{x + y})\) 级问题转化为 \(O(max(a^{x}, a^{y}))\) 级问题。

以上是一些经验主义的东西。

接下来介绍实际的解法。


考虑带余整除法 \(v = 2^{k} \cdot x + r \ (0 \leq r < 2^{k})\) 。其中 \(2^k \leq N\)\(k\) 为常数。

每个组(每个块)余数取满 \(0 \sim 2^{k} - 1\) ,则 \(0 \sim N\) 可以分成 \(\lceil N / 2^{k} \rceil\) 个块。

根据 \(x = 0, 1, 2, \cdots, \lceil N / 2^{k} \rceil - 1\) 对每个块编号,分布如下:

\[\begin{aligned} &[0 \cdot 2^{k} + 0, 0 \cdot 2^{k} + 1, \cdots, 0 \cdot 2^{k} + 2^{k} - 1] \\ &[1 \cdot 2^{k} + 0, 1 \cdot 2^{k} + 1, \cdots, 1 \cdot 2^{k} + 2^{k} - 1] \\ &[2 \cdot 2^{k} + 0, 2 \cdot 2^{k} + 1, \cdots, 2 \cdot 2^{k} + 2^{k} - 1] \\ &\vdots \\ &[m \cdot 2^{k} + 0, m \cdot 2^{k} + 1, \cdots, m \cdot 2^{k} + q = N \ (0 \leq q < 2^{k})] \\ \end{aligned} \]

\(x = 0, 1, 2, \sim \lceil N / 2^{k} \rceil - 2\) 的块一定都完整。
\(x = \lceil N / 2^{k} \rceil - 1\) 块可能不完整,即 \(r\) 不能取满 \(0, 1, \cdots, 2^{k} - 1\)

  • 考虑某个完整的块,即 \(0 \leq x < \lceil N / 2^{k} \rceil - 1\)

    由于 \(r\) 不超过 \(k\) 位,则 \(popcount(v = 2^{k} \cdot x + r) = popcount(v = (x << k) + r) = popcount(x) + popcount(r)\)

    一个块对应唯一 \(x\) ,则 \(popcount(x)\) 已知。这个块的贡献是:

    \[\sum_{ \substack{ r = 0, \\ popcount(x) + popcount(r) \equiv 1 (\bmod 2) } }^{2^{k} - 1} x \cdot 2^{k} + r \]

    考虑 \(k\) 个位置,选择一些位置为 \(1\) ,否则为 \(0\) ,容易证明(并且早就知道):

    \[\begin{aligned} \binom{k}{0} + \binom{k}{2} + \binom{k}{4} + \cdots \binom{k}{2 \lfloor k / 2 \rfloor} + \binom{k}{1} + \binom{k}{3} + \binom{k}{5} + \cdots \binom{k}{2 \lceil k / 2 \rceil - 1} = \sum_{i = 0}^{k} \binom{k}{i} = 2^{k} \\ \\ \binom{k}{0} + \binom{k}{2} + \binom{k}{4} + \cdots \binom{k}{2 \lfloor k / 2 \rfloor} = \binom{k}{1} + \binom{k}{3} + \binom{k}{5} + \cdots \binom{k}{2 \lceil k / 2 \rceil - 1} = 2^{k - 1} \\ \end{aligned} \]

    于是这个块的贡献是:

    \[\begin{aligned} &x \cdot 2^{k} \cdot 2^{k - 1} + \sum_{ \substack{ r = 0, \\ popcount(x) + popcount(r) \equiv 1 (\bmod 2) } }^{2^{k} - 1} r \\ &= x \cdot 2^{k} \cdot 2^{k - 1} + \begin{cases} \sum_{ \substack{ r = 0, \\ popcount(r) \equiv 0 (\bmod 2) } }^{2^{k} - 1} r,\ popcount(x) \equiv 1 (\bmod 2); \\ \sum_{ \substack{ r = 0, \\ popcount(r) \equiv 1 (\bmod 2) } }^{2^{k} - 1} r,\ popcount(x) \equiv 0 (\bmod 2). \\ \end{cases} \end{aligned} \]

    这里我们已经可以 \(O(2^{k})\) 预处理

    \[\begin{aligned} S_{even} = \sum_{ \substack{ r = 0, \\ popcount(r) \equiv 0 (\bmod 2) } }^{2^{k} - 1} r \\ S_{odd} = \sum_{ \substack{ r = 0, \\ popcount(r) \equiv 1 (\bmod 2) } }^{2^{k} - 1} r \\ \end{aligned} \]

    总共有 \(\lceil N / 2^{k} \rceil - 1\) 个块。

  • 考虑最后一个块,即 \(x = \lceil N / 2^{k} \rceil - 1\)
    可以暴力遍历 \(r \in [x \cdot 2^{k} + 0, N]\) ,若 \(popcount(x)\)\(popcount(r)\) 的奇偶性不同,则对答案贡献 \(x \cdot 2^{k} + r\)

综上,时间复杂度 \(O(max(N / 2^{k}, 2^{k}))\) 。如果把 \(k\) 取成 \(N\) 的二进制表示的一半,由 \(2^{a} \cdot 2^{b} = 2^{a + b}\) ,时间复杂度为 \(O(\sqrt{N})\)

Code
#include<iostream>
#include<cassert>const int32_t K = 16;
const int64_t BLOCK = int64_t(1) << K;int64_t S_even, S_odd;int64_t S(int64_t N) {if (N == 0) return 0;int64_t M = (N + BLOCK - 1) / BLOCK;int64_t rem = N % BLOCK;int64_t ret = 0;assert(M >= 1);for (size_t x = 0; x < M - 1; x++) {ret += int64_t(x) * (1 << K) * (1 << K - 1) + (__builtin_popcount(x) == 0 ? S_odd : S_even);}int32_t x = M - 1;for (size_t r = 0; r <= rem; r++) if ((__builtin_popcount(r) + __builtin_popcount(x) ) % 2 == 1) {ret += x * BLOCK + r;}return ret;
}int main(){std::cin.tie(nullptr)->std::ios::sync_with_stdio(false);int64_t D, U;std::cin >> D >> U;for (size_t i = 0; i < BLOCK; i++) {if (__builtin_popcount(i) % 2 == 0) S_even += i;if (__builtin_popcount(i) % 2 == 1) S_odd += i;}std::cout << S(U) - S(D - 1) << "\n";return 0;
}

\(k \geq 2\) ,可以证明(有时间再说,有简单但是很长的构造,也有很短但是用生成函数构造)

\[\sum_{ \substack{i = 0, \\ popcount(i) \equiv 0 (\bmod 2) } }^{2^{k} - 1 } i = \sum_{ \substack{ i = 0, \\ popcount(i) \equiv 0 (\bmod 2) } }^{2^{k} - 1} i = \binom{2^{k}}{2} / 2 = 2^{k - 2} \cdot (2^{k} - 1) \]

那么代码可以优化成:

Code
#include<iostream>
#include<cassert>const int32_t K = 16;
const int64_t BLOCK = int64_t(1) << K;int64_t S(int64_t N) {if (N == 0) return 0;int64_t M = (N + BLOCK - 1) / BLOCK;int64_t rem = N % BLOCK;int64_t ret = 0;assert(M >= 1);for (size_t x = 0; x < M - 1; x++) {ret += int64_t(x) * (1 << K) * (1 << K - 1) + int64_t(1) * (1 << K - 2) * ((1 << K) - 1);}int32_t x = M - 1;for (size_t r = 0; r <= rem; r++) if ((__builtin_popcount(r) + __builtin_popcount(x) ) % 2 == 1) {ret += x * BLOCK + r;}return ret;
}int main(){std::cin.tie(nullptr)->std::ios::sync_with_stdio(false);int64_t D, U;std::cin >> D >> U;std::cout << S(U) - S(D - 1) << "\n";return 0;
}

最后我突然发现好像能从 \(O(\sqrt{N})\) 优化到 \(O(1)\) …… 后面再说。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/937195.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

精确率

2025.10.15 1.精确率是指正确预测的正样本数与所有预测为正样本的比率,反映了模型预测为正样本的准确性

FBAM 论文浅析

这篇论文对当前以Transformer为主流的大模型基础架构提出了深刻的反思与挑战。它论证了纯粹并行化的模型在理论上存在表达能力的上限,并提出了一种融合并行与递归优势的新架构——帧动作模型(Frame-based Action Mod…

2025年上海律师服务最新权威推荐榜:经侦律师,民事纠纷律师,刑事律师,经济律师,婚姻律师,法务律师,负债律师事务所专业实力与口碑深度解析

2025年上海律师服务最新权威推荐榜:经侦律师,民事纠纷律师,刑事律师,经济律师,婚姻律师,法务律师,负债律师事务所专业实力与口碑深度解析在当今复杂多变的法律环境中,上海作为中国的经济与金融中心,对专业法律…

2025年冲压件厂家最新权威推荐榜:新能源/光伏/精密/异形/五金/铝/汽配/不锈钢/家具冲压件优质供应商精选

2025年冲压件厂家最新权威推荐榜:新能源/光伏/精密/异形/五金/铝/汽配/不锈钢/家具冲压件优质供应商精选行业背景与发展趋势冲压加工作为现代制造业的基础工艺,在新能源、光伏、汽车、家具等领域的应用日益广泛。随着…

前端知识图谱

一、JavaScript基础 变量和类型 ● 1.JavaScript规定了几种语言类型 ● 2.JavaScript对象的底层数据结构是什么 ● 3.Symbol类型在实际开发中的应用、可手动实现一个简单的Symbol ● 4.JavaScript中的变量在内存中的具…

软考二

软考二Posted on 2025-10-15 00:41 心默默言 阅读(0) 评论(0) 收藏 举报1. 基本概念与算法1.1 数据元素与数据项1.2 数据结构1.3 算法

UVa(紫书)做题记录

第八章:高效算法设计 UVA11093 Just Finish it up 最直接的办法:选取正收益的点开始,O(n) judge。但有个必须注意到的性质,即如果一个起点不合法,那么刚才扫过的所有点不不合法。于是时间复杂度就降下来了。明明就…

MyBatis 延迟加载使用及原理 - Higurashi

一、延迟加载是什么? 延迟加载(Lazy Loading)又称“惰性加载”,指的是:当查询一个对象时,不立即加载它的关联对象(如一对多、多对一关系),而是在第一次真正使用该关联对象时才去执行 SQL 查询加载它。举个例子…

ADC-过零检测详解

转载自:https://mbb.eet-china.com/tech/t1/177081.html1、反电动势波形的起源 下图展示了内转子磁极的磁感应强度B的分布情况。定义磁感应强度方向向外为正 在0的时候,处于正反方向交界处,磁感应强度为零; 然后开…

今日小雨

喜欢泥土的香气 傍晚的微风 夹杂着清新与沉闷之感 不必要的话不说 有些话没必要说 所做的目的懒得过问 回避过问 大觉一场

内网穿透进阶:让 frpc 只代理「真正在线」的端口

一条脚本搞定「端口探活 + 配置热更新 + 服务保活」,彻底告别手动重启与爆炸日志。一、痛点:静态配置的尴尬本地服务没启动,frpc 仍疯狂重试,日志秒级刷屏;新增/下线服务要手动改 TOML → 重启,极易遗忘;服务异…

规则逻辑与人文逻辑的统一:AI元人文构想的演进之路

规则逻辑与人文逻辑的统一:AI元人文构想的演进之路 在人工智能发展的关键转折点,我们面临着深刻的认知跃迁:规则逻辑与人文逻辑并非对立的两极,而是智能进化道路上相互依存、彼此成就的必然维度。AI元人文构想以其…

2023 ICPC Jinan

2023 ICPC Jinan ICPC Jinan G 考虑找矛盾。首先对于同一行,翻转和不翻是一个矛盾,对于相异的行,若一行的翻转或不反转会使同一列产生多余的 1,则又是一个矛盾。将每一行拆成两个点,一个点代表不翻转该行,一个点…

二叉树中和为目标值的路径

LCR 153. 二叉树中和为目标值的路径 LCR 153. 二叉树中和为目标值的路径参考题解前言 该题考察二叉树中的回溯,使用先序遍历以及路径记录 先序遍历:根左右 路径记录:通过一个“中间人”(path)来记录当前的路径和,…

动态库的调用方式

在 Linux 中,动态库(.so文件)的调用方式主要有两种:编译时链接(隐式调用)和运行时加载(显式调用)。 一、编译时链接(隐式调用) 这种方式在编译阶段就指定动态库,程序启动时会自动加载依赖的动态库,适用于已…

动态库的调用方式

在 Linux 中,动态库(.so文件)的调用方式主要有两种:编译时链接(隐式调用)和运行时加载(显式调用)。 一、编译时链接(隐式调用) 这种方式在编译阶段就指定动态库,程序启动时会自动加载依赖的动态库,适用于已…

云原生技术概览

云原生技术概览书籍:https://jimmysong.io/kubernetes-handbook/从云计算到微服务再到云原生计算 下面将从云计算的发展历程引入云原生计算 云计算介绍 云计算演进历程云计算就是一种配置资源的方式,根据资源配置方式…

OAM角色定义

OAM角色定义https://github.com/oam-dev/spec/blob/master/introduction.md关注点分离 开放应用程序模型提出了开发人员负责的部分与平台工程师负责的部分之间明确的关注点分离。 Open Application Model proposed a c…

OCI

OCI【译者的话】本文介绍了OCI运行时和镜像规范,以及在过去的一段时间里大家对该规范的一些误解。OCI规范制订工作尚未落幕,未来也将对容器产生更加深远的影响。 【3 天烧脑式基于Docker的CI/CD实战训练营 | 北京站】…

消灭重复代码的最佳实践

消灭重复代码的最佳实践代码重复本身不可怕,可怕的是漏改或改错。消灭重复代码,降低改动可能引入的风险。学习笔记:https://time.geekbang.org/column/article/228964工厂模式 + 模板方法 消除 if else 和重复代码 …