一.位运算简介:
任何信息在计算机中都是采用二进制表示的,数据在计算机中是以补码形式存储的,位运算就是直接对整数在内存中的二进制进行运算。由于位运算直接对内存数据进行操作,不需要直接转换成十进制,因此,处理速度非常快,在信息学竞赛中往往可以优化理论时间复杂度的系数。
c++提供了按位与(&)、按位或(|)、按位异或(^)、取反(~)、左移(<<)、右移(>>)这6种运算符。
1.按位与(&)
“ a a a & b b b ”是指将参与运算的两个整数用二进制进行“与”的操作,如果值都为一就输出1,否则为0
2.按位或(|)
“ a a a | b b b ”是指将参与或运算的两个整数用二进制进行“或”的操作,如果值有一个为一就为1,如果两个都是0,那就是0
3.按位异或(^)
“ a a a ^ b b b ”是指将参与异或的两个整数用二进制进行“异或”的操作,如果值不一样为1,否则位0
4.取反(~)
“ ~ a a a ”是指将参与取反的一个整数用二进制进行“取反”的操作,把a的二进制值反过来,为1取反完就为0,为0取反完就为1
5.左移(<<)
“ a a a << b b b ”是指将参与左移的两个数用二进制进行“左移”的操作,把 a a a 的二进制值向左移动 b b b 位
6.右移(>>)
“ a a a >> b b b ”是指将参与右移的两个数用二进制进行“右移”的操作,把 a a a 的二进制值向右移动 b b b 位
二.位运算的应用
例题一:枚举子集
题目描述
给定
n
n
n 个元素,输出
n
n
n 个元素构成的集合的所有子集。简化:以
n
n
n 个连续的 0/1
代表第
i
i
i 个元素是否选中(0
:未选中,1
:选中)。
输入格式
一行,一个正整数 n ( n < 20 ) n(n<20) n(n<20) 。
输出格式
输出共
2
n
2^n
2n 行,每行一个 0/1
构成的字符串,表示子集。
按字典序输出。
样例 #1
样例输入 #1
4
样例输出 #1
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111
这道题要用到左移( i i i & ( 1 (1 (1 << j ) j) j)来解题
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin>>n;
for(int i=0;i<(1<<n);i++)
{
for(int j=n-1;j>=0;j--) //这里要从小到大(从0001)开始判断
{
if(i&(1<<j)) //判断i个元素是否选中
{
cout<<1; //是就输出1
}
else
{
cout<<0; //不是输出0
}
}
cout<<'\n'; //不能用endl,因为endl比‘\n’慢100毫秒,在此题中会超时(TLE)
}
return 0;
}
例题二:小书童——刷题大军
题目描述
小A“刷题”十分猖狂,明目张胆地“刷题”。他现在在小书童里发现了n样他喜欢的“题目”,每“题”都有他的需要时间,而老师布置了 m m m 项作业,每项作业都有它的需要时间及分值,老师规定 k k k 分以上(包括 k k k 分)算及格。小A只剩 r r r 个单位时间,他想在及格的基础上更多地“刷题”。
输入格式
第一行: n , m , k , r n,m,k,r n,m,k,r 。第二行: n n n 个数,代表每“题”他的需要时间。第三行: m m m 个数。表示每项作业它的需要时间。第四行: m m m 个数。代表每项作业它的分值。
输出格式
一个数,代表小A能刷几道题
样例 #1
样例输入 #1
3 4 20 100
15 20 50
10 15 40 40
5 5 10 15
样例输出 #1
2
提示
没有不能及格的情况
对于
100
100
100% 的数据,
n
≤
10
,
m
≤
10
,
k
≤
50
,
r
≤
150
n≤10,m≤10,k≤50,r≤150
n≤10,m≤10,k≤50,r≤150
这道题要先做完作业后用最小的时间做最多的题
#include<bits/stdc++.h>
using namespace std;
int n,m,k,r,t[100],c[100],v[100],ans=1e9; //ans的值要定义的足够大
int main()
{
cin>>n>>m>>k>>r;
for(int i=1;i<=n;i++)
{
cin>>t[i]; //代表每“题”他的需要时间
}
for(int i=1;i<=m;i++)
{
cin>>c[i]; //表示每项作业它的需要时间
}
for(int i=1;i<=m;i++)
{
cin>>v[i]; //代表每项作业它的分值
}
for(int i=0;i<(1<<m);i++){
int sum=0, time=0;
for(int j=0;j<m;j++){
if(i&(1<<j)){ //判断
sum += v[j+1];
time += c[j+1];
}
}
if(sum>=k && time<=r){
ans = min(ans, time); //在时间里找最小值
}
}
r-=ans;
sort(t+1,t+n+1);
int cnt=0;
for(int i=1;i<=n;i++){
if(r>=t[i]){
cnt++; //找出最多能做几道题
r -= t[i];
}else{
break;
}
}
cout<<cnt<<endl;
return 0;
}