关于二进制的规律

关于二进制的规律

打完第二周的牛客萌新联赛出现了这个的板子,于是趁着机会对二进制的规律进行总结。可以和下一篇的B题结合着看,本篇也是为了让下一篇不显得太过冗余

规律总结

二进制的每一位都遵循固定周期,低位周期短,高位周期长,且呈倍数关系。通过 0-15 的二进制直观感受:

十进制 二进制 第 0 位(个位) 第 1 位(2 位) 第 2 位(4 位) 第 3 位(8 位)
0 0000 0 0 0 0
1 0001 1 0 0 0
2 0010 0 1 0 0
3 0011 1 1 0 0
4 0100 0 0 1 0
5 0101 1 0 1 0
6 0110 0 1 1 0
7 0111 1 1 1 0
8 1000 0 0 0 1
9 1001 1 0 0 1
10 1010 0 1 0 1
11 1011 1 1 0 1
12 1100 0 0 1 1
13 1101 1 0 1 1
14 1110 0 1 1 1
15 1111 1 1 1 1

通过枚举我们可以比较直观的看到下面的规律:

  1. 第 k 位的周期是 2^(k+1)
    • 第 0 位(1 位):周期 2(0→1 交替)
    • 第 1 位(2 位):周期 4(0→0→1→1 重复)
    • 第 2 位(4 位):周期 8(0→0→0→0→1→1→1→1 重复)
    • 以此类推,高位周期是低位的 2 倍。
  2. 周期内的规律
    每个周期中,前半段(2^k 个数)该位为 0,后半段(2^k 个数)为 1。

二进制位的变化具有周期性 。以第 k 位为例:

  • 周期长度为 2^(k+1)
  • 在每个周期内,前 2^k 个数的第 k 位为 0 ,后 2^k 个数的第 k 位为 1

例如:

  • k=0(最低位)时,周期长度为 2^1=2,序列为 0,1,0,1,0,1,...
  • k=1(次低位)时,周期长度为 2^2=4,序列为 0,0,1,1,0,0,1,1,...
  • k=2(第三位)时,周期长度为 2^3=8,序列为 0,0,0,0,1,1,1,1,...

有了上面的介绍,相信应该对二进制的规律有了直观的感受,下面有两道相关的题目。

小蓝的二进制询问

来源:D-小蓝的二进制询问_河南萌新联赛2024第(一)场:河南农业大学

思路

本题就是利用此规律求解的纯板子题

先求周期,再求余下的部分。最后将周期内的1和余下的1全部相加求解。将原来的O(n)优化到了O(60)

代码

cpp 复制代码
int count(int k, int x)
{
	int t=1LL<<(k+1);//计算周期
	int full=(x+1)/t;//整周期的个数
	int re=x+1-t*full;//计算余下个数
	return (t*full/2+max(0LL, re-t/2))%mod;
	//整周期中1的个数+剩余一段1的个数
	//例如k=2:周期为0,0,0,0,1,1,1,1·····
	//周期为8,可以观察到一个周期内前一半为0,后一半为1根据此规律进行计算
}
void solve()
{
	cin >> l >> r;
	int ans=0;
	for(int k=0; k<=60; k++)//注意:别开大了,不然超long long了
	{
		ans+=count(k,r)-count(k,l-1);//将区间内在k位上1的个数相加
		ans%=mod;
	}
	cout << ans << endl;
}

累加器

来源:F-累加器_河南萌新联赛2024第(三)场:河南大学

思路

这题虽然问法变了,从问统计1的个数变成了会变化多少次,其实本质都是围绕着二进制的规律展开的。

一个周期有相同个数的0和1,那么一个周期就可以分成两半。那么变化周期就是原周期的两倍。每个变化周期就会变一次,利用此规律就能很容易解决

代码

cpp 复制代码
// 计算第k位在累加过程中翻转的次数
int count(int k)
{
    if(k == 0) return y; // 最低位每次加1必翻转,共y次
    int t = 1LL << k; //变化周期为2^k
    int cnt1 = r / t; //0~r变化次数
    int cnt2 = l / t; //0~l变化次数
    return cnt1 - cnt2;    // 区间[l, r]内的翻转次数
}

void solve()
{
    cin >> x >> y;
    l = x;
    r = x + y;
    int ans = 0;
    for(int k = 0; k <= 31; k++)
        ans += count(k);

    cout << ans << endl;
}

好了,本篇就到此结束。下一篇的B题也是此类型,敬请期待···

相关推荐
周杰伦_Jay32 分钟前
【图文详解】强化学习核心框架、数学基础、分类、应用场景
人工智能·科技·算法·机器学习·计算机视觉·分类·数据挖掘
violet-lz1 小时前
Linux静态库与共享库(动态库)全面详解:从创建到应用
算法
贝塔实验室1 小时前
ADMM 算法的基本概念
算法·数学建模·设计模式·矩阵·动态规划·软件构建·傅立叶分析
235161 小时前
【LeetCode】3. 无重复字符的最长子串
java·后端·算法·leetcode·职场和发展
微笑尅乐2 小时前
神奇的位运算——力扣136.只出现一次的数字
java·算法·leetcode·职场和发展
吃着火锅x唱着歌2 小时前
LeetCode 3105.最长的严格递增或递减子数组
算法·leetcode·职场和发展
小卡皮巴拉2 小时前
【笔试强训】Day1
开发语言·数据结构·c++·算法
初圣魔门首席弟子2 小时前
switch缺少break出现bug
c++·算法·bug
山烛2 小时前
OpenCV:人脸识别实战,3 种算法(LBPH/EigenFaces/FisherFaces)代码详解
opencv·算法·计算机视觉·人脸识别·lbph·eigenfaces·fisherfaces
吃着火锅x唱着歌3 小时前
LeetCode 2765.最长交替子数组
算法·leetcode·职场和发展