B3919 [语言月赛 202401] 二进制与一 题解

142 阅读2分钟

[语言月赛 202401] 二进制与一

题目描述

给定一个正整数 nn,以及操作次数 qq。对于每次操作,给出一个正整数 kk,要求:让 nn 加上一个非负整数 xx,使得 nn 在二进制下的第 kk 位(从右往左数)是 11,并在符合要求的情况下,令 xx 最小。

请注意,每次操作都会让 nn 变为 n+xn + x,会影响后续操作。

小山需要求出,所有的 xx 之和是多少。

输入格式

输入共 q+1q + 1 行。

第一行两个整数 nnqq
接下来 qq 行,每行一个正整数 kk,表示要让 nn 在二进制下从右往左数的第 kk 位是 11

输出格式

一行一个整数,表示所有的 xx 之和。

样例 #1

样例输入 #1

5 3
2
3
4

样例输出 #1

3

提示

样例 1 说明

55 在二进制下是 101101

  • 对于第一次操作,需要让 101101 的第二位变为 11,则需让 101101 加上 11,变为 110110
  • 对于第二次操作,需要让 110110 的第三位是 11,由于 110110 的第三位本身就是一,所以无需改变;
  • 第三次操作同理,需要让 110110 加上 22

最终输出结果是 1+0+2=31+0+2=3

思路分析:

  • 当第k位是1的情况,我们此时不需要做任何操作,n & (1<<k-1) 用来判断 第k是否为1
  • 当第k位不为1的情况,此时需要加上 n % (1<<k-1) 的数因为对k后面的数组成的取模后可以得到,相加后产生k位为1的最小值。
#include<iostream>
using i64 = long long;


int main(){
	std::ios::sync_with_stdio(0);
	std::cin.tie(0),std::cout.tie(0);
	i64 n,q;
	std::cin >> n >> q;
	i64 x = 0;
	while(q--){
		i64 k;
		std::cin >> k;
		--k;
		if(n & (1ll<<k)) continue;
		i64 st = n % (1ll << k);  
		x += (1ll << k) - st;
		n += (1ll << k) - st;
	}
	std::cout << x << '\n';
	return 0;
}