[语言月赛 202401] 二进制与一
题目描述
给定一个正整数 ,以及操作次数 。对于每次操作,给出一个正整数 ,要求:让 加上一个非负整数 ,使得 在二进制下的第 位(从右往左数)是 ,并在符合要求的情况下,令 最小。
请注意,每次操作都会让 变为 ,会影响后续操作。
小山需要求出,所有的 之和是多少。
输入格式
输入共 行。
第一行两个整数 和 。
接下来 行,每行一个正整数 ,表示要让 在二进制下从右往左数的第 位是 。
输出格式
一行一个整数,表示所有的 之和。
样例 #1
样例输入 #1
5 3
2
3
4
样例输出 #1
3
提示
样例 1 说明
在二进制下是 。
- 对于第一次操作,需要让 的第二位变为 ,则需让 加上 ,变为 ;
- 对于第二次操作,需要让 的第三位是 ,由于 的第三位本身就是一,所以无需改变;
- 第三次操作同理,需要让 加上 。
最终输出结果是 。
思路分析:
- 当第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;
}