前置知识

\(\text{popcount}(n)\) 表示将 \(n\) 转为二进制后的数中 \(1\) 的个数。

结论

\[\sum_{i=1}^{n} \text{ popcount}(i)=\sum_{i=1}^{\left \lceil \log_{2}{n} \right \rceil-1 } \left [ (n>>(i-1))\text{&}1==1 \right ] \times (i\times 2^{i-1}+2^{i}\times \text {popcount}(n>>i)
\]

其中 $ \left [ (n>>(i-1))\text{&}1==1 \right ]$ 表示 \(n\) 转成二进制以后第 \(i\) 位是不是 \(0\)。

原理

首先我们需要知道这个东西:

__builtin_popcount(x)

可恶怎么又是 STL

他的作用就是求出 \(x\) 的 \(\text{popcount}\) 值,这个东西好像很快我们先把他当作 \(O(1)\) 的。

接下来我们考虑用 \(O(1)\) 的时间来求得

\[\sum_{i=0}^{2^{k}-1} \text{popcount}(i)
\]

的做法。

这里以 $ \left [ 0,2^{5}-1 \right ] $ 为例。

先把所有的数都给列出来。

然后我们可以看到最低位的规律。

依次向后走。

我们可以看到每一位里面都是一半是 \(0\),一半是 \(1\)。

因此我们可以得到下面的公式:

\[\sum_{i=0}^{2^{k}-1} \text{popcount}(i)=k\times 2^{k-1}
\]

下面以 \((11010110)_{2}=(214)_{10}\) 为例。

其第一位为 \(1\),所以我们直接计算 \((00000000)_{2}\text{~}(01111111)_{2}\) 的 \(\text{popcount}\) 和,也就是 \(0\times 2^{7}+7\times 2^{6}\)。

其第二位为 \(1\),所以我们直接计算 \((10000000)_{2}\text{~}(10111111)_{2}\) 的 \(\text{popcount}\) 和,也就是 \(1\times 2^{6}+6\times 2^{5}\)。

其第三位是 \(0\),对答案没有贡献。

其第四位为 \(1\),所以我们直接计算 \((11000000)_{2}\text{~}(11001111)_{2}\) 的 \(\text{popcount}\) 和,也就是 \(2\times 2^{4}+4\times 2^{3}\)。

其第五位是 \(0\),对答案没有贡献。

其第六位为 \(1\),所以我们直接计算 \((11010000)_{2}\text{~}(11010011)_{2}\) 的 \(\text{popcount}\) 和,也就是 \(3\times 2^{2}+2\times 2^{1}\)。

其第七位为 \(1\),所以我们直接计算 \((11010100)_{2}\text{~}(11010101)_{2}\) 的 \(\text{popcount}\) 和,也就是 \(4\times 2^{1}+1\times 2^{0}\)。

其第八位是 \(0\),对答案没有贡献。

但其实我们只需要处理 \([0,n)\) 这个区间分段即可。

最后再加上 \(\text{popcount}((11010110)_{2})=5\)。

最终结果就是:

\[0\times 2^{7}+7\times 2^{6}+1\times 2^{6}+6\times 2^{5}+2\times 2^{4}+4\times 2^{3}+3\times 2^{2}+2\times 2^{1}+4\times 2^{1}+1\times 2^{0}+\text{popcount}((11010110)_{2})
\]
\[=448+256+64+16+9+5
\]
\[=798
\]

因为 \(\text{popcount}(0)=0\),所以统计不统计都可以。

代码

scanf("%d", &n);
long long tot = 0;
int cnt = 0;
int x = n;
while(x)
{
if(x & 1)
tot += (cnt * (1 << (cnt - 1))) + (1 << cnt) * __builtin_popcount(x >> 1);
x >>= 1;
cnt++;
}
tot += __builtin_popcount(n);
printf("%lld ", tot);

转载自:https://kaiserwilheim.github.io/OI/fast-popcnt-sum/

虽然是转载但是 \(\LaTeX\) 都是我自己打的QAQ

快速求popcount的和的更多相关文章

  1. 快速求n的质因子(数论)

    快速求n的质因子 如何尽快地求出n的质因子呢?我们这里又涉及两个好的算法了! 第一个:用于每次只能求出一个数的质因子,适用于题目中给的n的个数不是很多,但是n又特别大的 #include<std ...

  2. 【GDOI 2011 DAY2 T3】零什么的最讨厌了 (快速求阶乘、中国剩余定理)

    问题描述: 林记在做数学习题的时候,经常遇到这种情况:苦思冥想了很久终于把问题解出来,结果发现答案是0,久而久之林记在得到习题答案是0的时候就没有了做出一道难题的成就感.于是林记决定:以后出题,答案一 ...

  3. 快速求幂(Quick Exponentiation)

    接触ACM没几天,向各路大神求教,听说ACM主要是研究算法,所以便开始了苦逼的算法学习之路.话不多说,RT所示,学习快速求幂. 在头文件<math.h>或是<cmath>中,d ...

  4. hdu 2814 快速求欧拉函数

    /** 大意: 求[a,b] 之间 phi(a) + phi(a+1)...+ phi(b): 思路: 快速求欧拉函数 **/ #include <iostream> #include & ...

  5. NYOJ--102--次方求模(快速求幂取模)

    次方求模 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述 求a的b次方对c取余的值   输入 第一行输入一个整数n表示测试数据的组数(n<100)每组测试只有一 ...

  6. javascript中快速求数组的全部元素的相加之和

    js中快速求数组的全部元素的相加之和: var arr = [1,2,3,4,5];var sum = eval(arr.join('+')); console.log(sum); 运行结果: 15

  7. HDU 2035 人见人爱A^B(二分求幂,快速求幂)

    题意:求A的B次方的后三位数字 思路1:常规求幂,直接取余求解 代码: #include<iostream> #include<cstdio> using namespace ...

  8. 快速求排列C(m,n)加取模

    快速求排列组合C(m,n)%mod 写在前面: 1. 为防止产生n和m的歧义,本博文一律默认n >= m 2. 本博文默认mod = 10^6+3 3. 本博文假设读者已知排列组合公式 C(m, ...

  9. 线性齐次递推式快速求第n项 学习笔记

    定义 若数列 \(\{a_i\}\) 满足 \(a_n=\sum_{i=1}^kf_i \times a_{n-i}\) ,则该数列为 k 阶齐次线性递推数列 可以利用多项式的知识做到 \(O(k\l ...

  10. Quick Pow: 如何快速求幂

    今天讲个有趣的算法:如何快速求 \(n^m\),其中 n 和 m 都是整数. 为方便起见,此处假设 m >= 0,对于 m < 0 的情况,求出 \(n^{|m|}\) 后再取倒数即可. ...

随机推荐

  1. 【Linux】虚拟机CentOS 7 磁盘扩容

    [Linux]虚拟机CentOS 7 磁盘扩容 在有些时候,自己或者公司开的虚拟机的磁盘在一开始的时候没规划好,或者有磁盘扩容的需求(其实在系统日常运维的时候这个需求时常出现),那么这个时候又该怎么处 ...

  2. 关于C#的async和await

    1.async 与 await需要同时出现在方法中  如下图所示 public static async Task b() { await Task.Run(() => { //Thread.S ...

  3. Java基础学习——循环取最接近某个值的方法

    if(diff<mindiff) mindiff=diff;//循环取最小值 float value = (float) fenzi/fenmu;//整数相除结果会自动转换为整数.即使强制转换为 ...

  4. 服务器中VirtualBox子网访问

    本人常用的虚拟机软件是VirtualBox,由于笔记本性能,磁盘存储大下限制,以及VirtualBox客户机无法在多个设备间直接方便的使用等原因,我把几个虚拟的系统全部移动到便携式服务器中. 移动之后 ...

  5. Postgresql 或GreenPlum 查询结果部分字段转json格式并保留字段名(row_to_json)

    -- 一些搜索结果给出 部分字段转json保留原字段的方式是用子查询select row_to_json(t) from ( select id, text from words ) t 但是如果子查 ...

  6. mysql 存储国过程实现竖表变横表(将行数据值变为字段)

    示例: 表结构如下: CREATE TABLE `pressure` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增主键', `presurena ...

  7. mybaits-plus 部分注解说明

    参考: https://blog.csdn.net/qq_45684867/article/details/123951309

  8. DRF的视图与路由集Routers

    一 视图 Django REST framwork 提供的视图的主要作用: 控制序列化器的执行(检验.保存.转换数据) 控制数据库模型的操作 一 普通视图APIView 一 两个视图基类 1 APIV ...

  9. mysql zip安装步骤

    1. 官网下载社区版 https://dev.mysql.com/downloads/mysql/ 版本5.7或者8.0 2. 解压到指定的目录. 3.创建my.ini文件,编辑内容: [mysqld ...

  10. excel表格常用函数技巧大全 excel中最常用的30个函数分享

    excel中最常用的30个函数: 一.数字处理 1.取绝对值 =ABS(数字) 2.取整 =INT(数字) 3.四舍五入 =ROUND(数字,小数位数) 二.判断公式 1.把公式产生的错误值显示为空 ...