本文已参与「新人创作礼」活动,一起开启掘金创作之路。
蓝桥杯练习021
二进制表示中 “1” 的个数
任务介绍
请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。
例:9 的二进制表示为 1001,有 2 位是 1 ,所以函数返回 2。
知识点
- 知识点 1:进制
- 知识点 2:位运算
代码
#include<iostream>
#include<bitset>
using namespace std;
int main()
{
int n;
cin>>n;
int cnt=0;
cout<<bitset<32>(n)<<endl;
for(int i=0;i<32;i++){
if((n&(1<<i))==(1<<i))
cnt++;
}
cout<<cnt<<endl;
cnt=0;
for(int i=0;i<32;i++){
if(((n>>i)&1)==1)
cnt++;
}
cout<<cnt<<endl;
cnt=0;
while(n!=0){
n = ((n-1)&n);
cnt++;
}
cout<<cnt<<endl;
return 0;
}
如何用一条语句判断一个整数是不是2的整数次方?
二进制判断
if(((n-1)&n)==0)
显然,2 的整数次幂,其 2 进制表示有个特点就是只有一个 1,比如:
0000 1000 # 8
0001 0000 # 16
因此问题转换为判定整数的二进制表示中是否只有一个 1。
求整数二进制表示中有多少个 1,此前已经做过了。这里有个简单的方法:
表达式 x & (x-1) 可以消除 x 二进制中最末的 1 ,如果表达式计算后为 0 ,那就说明 x 的二进制表示中只有一个 1。
将整数的二进制奇偶位互换
任务介绍
请实现一个函数,输入一个整数,将该整数二进制表示中的奇偶位互换,返回互换后的整数。
例:100 运算后的结果为 152。
知识点
- 知识点 1:进制
- 知识点 2:位运算
代码
#include<iostream>
using namespace std;
int main()
{
int n;
cin>>n;
int os=n&0xaaaaaaaa;//1010//保留偶数位
int js=n&0x55555555;//0101//保留奇数位
cout<<((os>>1)^(js<<1))<<endl;
return 0;
}
蓝桥杯练习022
锻造兵器
题目描述
小明一共有 n 块锻造石,第 i块锻造石的属性值为 ai。
现在小明决定从这 n块锻造石中任取两块来锻造兵器。
通过周密计算,小明得出,只有当两块锻造石的属性值的差值等于 C,兵器才能锻造成功。
请你帮小明算算,他有多少种选取锻造石的方案可以使得锻造成功。
输入描述
第一行包含两个整数 n,C,其含义如题所述。
接下来一行包含 n 个整数,分别表示 a1,a2,…an.
1≤N≤2×105,∣ai∣≤104,0≤C≤10^9。
输出描述
输出共一行,包含一个整数,表示答案。
输入输出样例
示例 1
输入
6 3
8 4 5 7 7 4
输出
5
运行限制
- 最大运行时间:1s
- 最大运行内存: 128M
解题思路
大佬:这题如果用暴力法统计数对,很显然,复杂度为 O(n^2),超时。所以下面试试尺取法。
萌新:尺取法?em,首先第一步肯定是排序,那么对输入样例排序后得 {4 4 5 7 7 8},其中第一个 4 和后面两个 7 是两对,第二个 4 和后面两个 7 也是两对,共四对。这用尺取法该如何实现?
大佬:如果仅使用 i、j 两个指针,确实是无法实现的,但如果把后面两个 7看成一个整体,一起统计数对,是不是就可以了?我们可以用两个指针 j、k 指示这种区间,[j, k] 区间内每个数都相同,这个区间可以产生 k – j个数对。细节见下面的参考答案。使用三个指针,i 是主指针,从头到尾遍历 n 个数;j、k 是辅助指针,用于查找数字相同的区间 [j, k]。
萌新:哇哦,大佬 nb。
大佬:知道复杂度怎么算吧?
萌新:知道!代码只有一个 for 循环,且 j和 k 随着 i 递增,所以总复杂度为 O(n)。
代码
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 2e5 + 5;
int a[N];
int main (){
int n,c;
cin >> n >> c;
for(int i = 1 ; i <= n ; i++)
cin >> a[i];
sort(a + 1 , a + 1 + n);
long long ans = 0; //答案数量超过int,需要用long long
for(int i=1,j=1,k=1; i <= n ; i++) {
while(j <= n && a[j] - a[i] < c )
j++; //用j、k查找数字相同的区间
while(k <= n && a[k] - a[i] <= c)
k++; //区间[j,k]内所有数字相同
if(a[j]-a[i]==c && a[k-1]-a[i]==c && k-1>=1)
ans += k - j; //统计数对
}
cout << ans <<endl;
return 0;
}