2.25 日常(位运算)
来源:互联网 发布:桌面网络图标不见了 编辑:程序博客网 时间:2024/05/19 06:39
今天开始练习位运算,之前都是看课件,今天开始实战。
位操作(POJ - 3748)
其实这是道位运算的基本题,但是由于我之前并没有写过位运算,所以把思路想的特别复杂。又是循环又是加减,事实这些都可以运用左移和取反来操作。除此之外还有,在读入输入十六进制数时可以用%x。
第一个操作是将第x位变成0,我们就可以并一个数,这个数的第x位是0,其他全是1.即~(1<< x)。第二个操作分成两步,一步是将第y-2位变成0,这一步同第一个操作。另一步是将y和y-1位变成1,即或两个数,这两个数的第y位和第y-1位分别是1,其他数是0.即1<< y,1<< (y-1)。
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int x,y,n;int main(){ scanf("%x,%d,%d",&n,&x,&y); n=n&(~(1<<x)); n=n&(~(1<<(y-2))); n=n|(1<<y)|(1<<(y-1)); printf("%x",n);}
Binary Number (HDU - 3711)
题目大意:定义一种运算f,f(a,b)表示a和b的二进制数有几位是不同的。同时给定A,B两个集合,对于每一个B集合中的元素,需在A中找到一个元素和这个元素的f最小,如有多个则输出最小的一个。
因为这里的数据不大,可以直接暴力做,对于B中的每一元素进行枚举,用异或运算来判断两个元素用多少位相等,然后去最小的就可以。
同时要注意一个细节,输入中给定的A集合是无序的,我们要进行一次排序,我就是因为这个地方错了三次。而且异或之后求1的个数是有简便方法的,不需要对每一位进行操作。至于简便方法的实现就看我的代码。
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int T,n,m;int a[105],b[105];int main(){ scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]); sort(a+1,a+n+1); for(int i=1;i<=m;i++) scanf("%d",&b[i]); for(int i=1;i<=m;i++) { int mine=0x3fffffff,t; for(int j=1;j<=n;j++) { int cnt=0; int now=a[j]^b[i]; while(now)//这个就是求有多少个1的简便方法 { now=now&(now-1); cnt++; } if(cnt<mine) mine=cnt,t=a[j]; } printf("%d\n",t); } }}
An Easy Problem (POJ - 2453)
题目大意:给定一个数n,求一个比n大而且二进制数中的1的个数和n相等。
有上一题的基础这道题就很简单,只需每次加1,用上道题的方法判断就可以。
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int n,cnt;int main(){ while(1) { scanf("%d",&n); if(n==0) break; cnt=0; int t=n; while(t) { t&=t-1; cnt++; } for(int i=1;;i++) { int now=0; t=n+i; while(t) { t&=t-1; now++; } if(now==cnt) { printf("%d\n",n+i); break; } } }}
N皇后问题 (HDU - 2553)
这道题的位运算实现真的非常巧妙,用三个变量的二进制表示当前行可放的位置,然后进行枚举,推算出下一行可以放的位置。
在我的代码中h表示当前这一行可以放的位置,l和r分别表示主对角线和副对角线,三个量进行或运算取反在与总的方案数((1<< n)-1)并,就得到了当前行可以放的位置。
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;int n,ans;void dfs(int h,int l,int r){ int t=(1<<n)-1; if(h==t) { ans++; return; } int p=t&(~(h|l|r)); while(p) { int now=p&-p; p-=now; dfs(h+now,(l+now)>>1,(r+now)<<1); }}int main(){ while(1) { scanf("%d",&n); if(n==0) break; ans=0; dfs(0,0,0); printf("%d\n",ans); }}
The Number of set (HDU - 3006 )
题目大意:给定n个集合,求这些集合能组成多少个不同的集合。
因为每一个元素都不超过m,而且m最大为14,所以可以直接用二进制将一个集合表示出来。然后与之前所有的情况做或运算,得到的新集合打上标记,最后再来统计一共有多少个标记就可以了。
#include<cstdio>#include<cstring>#include<algorithm>#define MAXN (1<<14)+10using namespace std;int n,m,ans;bool vis[MAXN];int main(){ while(scanf("%d%d",&n,&m)!=EOF) { ans=0; memset(vis,0,sizeof vis); for(int i=1;i<=n;i++) { int t; scanf("%d",&t); int now=0; for(int j=1;j<=t;j++) { int x; scanf("%d",&x); now|=(1<<(x-1)); } vis[now]=1; for(int j=1;j<=MAXN;j++) if(vis[j]) vis[j|now]=1; } for(int i=1;i<=MAXN;i++) if(vis[i]) ans++; printf("%d\n",ans); }}
- 2.25 日常(位运算)
- C++中的位运算符(抄袭苟的日常)
- 位运算(技巧)
- 位运算(2)
- 位运算(3)
- 位运算(1)
- 位运算(2)
- 位运算知识点 (& ^ | )
- Interview(位运算)
- (6)位运算
- 位运算(1)
- & | ^ ~ << >> >>>(java位运算)
- java 位运算(位操作)
- POJ 3748 位操作(位运算)
- 位运算符(一):C/C++位运算符
- 位运算符介绍(二):Java位运算符
- 位运算符(一):C/C++位运算符
- 位运算符介绍(二):Java位运算符
- Codeforces Round #401 (Div. 2)(C,D,E)
- ServletConfig与ServletContext
- 指纹传感器和假指纹攻防技术
- 动态规划 数字三角形
- C#引用一例Form2调用Form1的函数包含 serialPort1.Write时
- 2.25 日常(位运算)
- esri-leaflet入门教程(4)-加载各类图层
- 树莓派常用配置集合
- android studio的安装过程
- java面向对象思想
- ffmpeg在arm64下编译
- 【程序】STM32使用SPI接口操作93C46存储器(非软件模拟)
- 获取版本名称和版本号
- poj1981(几何极限情况)