?裸的位运算的题目,要么用bitset直接修改,不过to_ullong()不知道为何炸了,只能用to_ulong()
?要么用运算符操作,挂运算符操作的代码:
#include<iostream>
#include<bitset>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
int main()
{
int r,x,y;
scanf("%x,%d,%d",&r,&x,&y);
r=(r&(~(1<<x)));//将第x位赋值为0
r=(r|(1<<y));//将第y位赋值为1
r=(r|(1<<(y-1)));
r=(r&(~(1<<(y-2))));
printf("%x\n",r);
return 0;
}
?新定义函数$f(a,b)$为a,b两数在二进制下不同数位的个数,给出m个a,和n次询问,询问给出数b,在a中找到一个数,使得$f(a,b)_{min}$
?计算$f(a,b)$可以直接选择用bitset暴力匹配,但更可以巧用位运算的性质:a^b可以使得位同为1,位异为0,再统计所以为1的数位即可。
#include<iostream>
#include<cstdio>
#include<bitset>
#include<cstring>
#include<string>
#include<algorithm>
#include<functional>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
int main()
{
int T;
while(~scanf("%d",&T))
{
while(T--)
{
ll a[20000],b;
memset(a,0,sizeof(a));
// memset(b,0,sizeof(b));
int m,n;
scanf("%d %d",&m,&n);
for(int i=0;i<m;i++)
scanf("%lld",&a[i]);
sort(a,a+m,greater<ll>());
for(int i=0;i<n;i++)
{
scanf("%lld",&b);
ll minn=INT_MAX,jmin=-1;
for(int j=0;j<m;j++)
{
ll tmp=a[j]^b;
bitset<1000> res(tmp);
int t=res.count();
if(t<=minn)
{
minn=t;
jmin=a[j];
}
}
printf("%lld\n",jmin);
}
}
}
return 0;
}
?给出数I,求出大于数I的最小数m,使得m表示成二进制形式时1的个数与I的相等
?考虑极端情形:当数位只有一其余均为0的时候,最小数m只可能为I左移一位的情形。即数m的最大范围为$[m+1,2m]$。故枚举即可。
#include<iostream>
#include<cstdio>
#include<bitset>
using namespace std;
typedef long long ll;
int main()
{
ll q;
while(~scanf("%lld",&q)&&q)
{
bitset<100> s(q);
int t=s.count();
for(int i=q+1;;i++)
{
bitset<100>r(i);
if(r.count()==t)
{
cout<<i<<endl;
break;
}
}
}
return 0;
}
?给出若干集合求可以组成的不同的并集的个数
?状态压缩裸题,将每个集合用二进制数位储存(bitset)并在输入过程中求并。最后统计
#include<bits/stdc++.h>
using namespace std;
int a[1<<15];
int main()
{
int n,m;
while(~scanf("%d %d",&n,&m)&&n&&m)
{
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++)
{
int t;
cin>>t;
bitset<100>q;
for(int i=0;i<t;i++)
{
int tmp;
cin>>tmp;
q[tmp-1]=1;
}
unsigned long res=q.to_ulong();
a[res]=1;
for(int i=0;i<(1<<m);i++)
{
if(a[i])
{
a[i|res]=1;
}
}
}
int cnt=0;
for(int i=0;i<(1<<m);i++)
{
if(a[i]) cnt++;
}
cout<<cnt<<endl;
}
return 0;
}
?黑白棋问题(关灯问题),比较好想的想法是dfs,不太好想的想法是位运算
dfs:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=10;
const int INF=0x3f3f3f;
const int r[5]={-1,0,0, 0,1};
const int c[5]={ 0,1,0,-1,0};
int grid[maxn][maxn];
int ans=INF;
bool judge()
{
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
if(grid[i][j]!=grid[0][0]) return false;
}
}
return true;
}
void flip(int x,int y)
{
for(int i=0;i<5;i++)
{
if(x+r[i]>=0&&x+r[i]<4&&y+c[i]>=0&&y+c[i]<4)
grid[x+r[i]][y+c[i]]=!grid[x+r[i]][y+c[i]];
}
}
void dfs(int x,int y,int t)
{
if(judge())
{
ans=min(ans,t);
return ;
}
if(x>3||y>3||x<0||y<0) return ;
int nx=(x+1)%4;
int ny=y+(x+1)/4;
dfs(nx,ny,t);
flip(x,y);
dfs(nx,ny,t+1);
flip(x,y);
return ;
}
int main()
{
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
char tmp;
cin>>tmp;
grid[i][j]=(tmp==‘b‘)?0:1;
}
}
dfs(0,0,0);
if(ans==INF) cout<<"Impossible\n";
else cout<<ans<<endl;
return 0;
}
#include<cstdio>
#include<cstdlib>
using namespace std;
int ans=999999;
int mi[16]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
void search(int x,int f,int st)/*x表当前第几位,f表棋盘状态,st代表翻转次数*/
{
if((f==65535)or(f==0))
{
if(st<ans) ans=st;
return;
}
if(x==17) return;
if(st>=ans) return;
search(x+1,f,st);
f^=(1<<((17-x)-1));//改变自己
if(x%4!=0) f^=(1<<((17-x-1)-1));//改变右边的
if(x%4!=1) f^=(1<<((17-x+1)-1));//改变左边的
if(x>4) f^=(1<<((17-x+4)-1));//改变上面的
if(x<=12) f^=(1<<((17-x-4)-1));//改变下面的
search(x+1,f,st+1);
}
int main()
{
int s=0;
for(int i=1;i<=4;i++)
{
for(int j=1;j<=4;j++)
{
char ch;
scanf("%c",&ch);
if(ch==‘b‘) s+=mi[16-4*i+4-j];/*把矩阵变成一个数,第i位为1代表第(i/4)行第(i%4)(0代表4)列是Black;*/
}
scanf("\n");
}
search(1,s,0);
if (ans==999999) printf("Impossible\n");
else printf("%d\n",ans);
return 0;
}
bfs+位运算
注意C++11结构体的新语法
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<bitset>
#include<stack>
#include<map>
#include<set>
using namespace std;
int n,m,t;
struct node
{
int x,y,t,k;
};
char Map[22][22];
bool vis[22][22][1030];
int dx[]={-1,0,0,1};
int dy[]={0,-1,1,0};
queue<node>Ac;
inline void init()
{
while(Ac.size()) Ac.pop();
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
cin>>Map[i][j];
if(Map[i][j]==‘@‘)
{
Ac.push(node{i,j,0,0});
vis[i][j][0]=1;
}
}
if(i!=n-1) getchar();
}
}
inline void bfs()
{
node now;
while(Ac.size())
{
now=Ac.front();
Ac.pop();
if(Map[now.x][now.y]==‘^‘&&now.t<t)
{
cout<<now.t<<endl;
return ;
}
for(int i=0;i<4;i++)
{
int tx=now.x+dx[i];
int ty=now.y+dy[i];
if(tx<0||ty<0||tx>=n||ty>=m||Map[tx][ty]==‘*‘||vis[tx][ty][now.k]) continue;
if(isupper(Map[tx][ty])&&!(now.k&1<<(Map[tx][ty]-‘A‘))) continue;
int k=now.k;
if(islower(Map[tx][ty]))
{
k=now.k|(1<<(Map[tx][ty]-‘a‘));
}
if(!vis[tx][ty][k])
{
vis[tx][ty][k]=1;
Ac.push(node{tx,ty,now.t+1,k});
}
}
}
puts("-1");
}
int main()
{
while(~scanf("%d%d%d\n",&n,&m,&t))
{
init();
bfs();
}
return 0;
}
八皇后问题,回溯打表或者位运算都要写熟
#include<bits/stdc++.h>
using namespace std;
int a[100],n,ans;
void dfs(int depth)
{
if(depth==n)
{
ans++;
return ;
}
else
{
for(int i=0;i<n;i++)
{
a[depth]=i;
bool flag=true;
for(int j=0;j<depth;j++)
{
if(a[j]==a[depth]||j-a[j]==depth-a[depth]||j+a[j]==depth+a[depth])
{
flag=false;
break;
}
}
if(flag) dfs(depth+1);
}
}
}
int main()
{
while(~scanf("%d",&n)&&n)
{
memset(a,0,sizeof(a));
ans=0;
dfs(0);
cout<<ans<<endl;
}
return 0;
}
位运算:
#include<bits/stdc++.h>
using namespace std;
int lim,sum;
void dfs(int row,int left,int right)
{
if(row==lim)
{
sum++;
return ;
}
else
{
int pos,p;
pos=lim&(~(row|left|right));
while(pos!=0)
{
p=pos&-pos;
pos=pos-p;
dfs(row+p,(left+p)<<1,(right+p)>>1);
}
}
}
int main()
{
int n;
while(~scanf("%d",&n)&&n)
{
sum=0;
lim=(1<<n)-1;
dfs(0,0,0);
cout<<sum<<endl;
}
return 0;
}
1.各种取位技巧,四种基本位运算(与或非异或)
2.快速幂
3.状态压缩与其在dp、搜索中的应用
4.lowbit运算,GCC内置函数
5.bitset的应用
---恢复内容结束---
# 位运算学习笔记(20180815)?裸的位运算的题目,要么用bitset直接修改,不过to_ullong()不知道为何炸了,只能用to_ulong()
?要么用运算符操作,挂运算符操作的代码:
#include<iostream>
#include<bitset>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
int main()
{
int r,x,y;
scanf("%x,%d,%d",&r,&x,&y);
r=(r&(~(1<<x)));//将第x位赋值为0
r=(r|(1<<y));//将第y位赋值为1
r=(r|(1<<(y-1)));
r=(r&(~(1<<(y-2))));
printf("%x\n",r);
return 0;
}
?新定义函数$f(a,b)$为a,b两数在二进制下不同数位的个数,给出m个a,和n次询问,询问给出数b,在a中找到一个数,使得$f(a,b)_{min}$
?计算$f(a,b)$可以直接选择用bitset暴力匹配,但更可以巧用位运算的性质:a^b可以使得位同为1,位异为0,再统计所以为1的数位即可。
#include<iostream>
#include<cstdio>
#include<bitset>
#include<cstring>
#include<string>
#include<algorithm>
#include<functional>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
int main()
{
int T;
while(~scanf("%d",&T))
{
while(T--)
{
ll a[20000],b;
memset(a,0,sizeof(a));
// memset(b,0,sizeof(b));
int m,n;
scanf("%d %d",&m,&n);
for(int i=0;i<m;i++)
scanf("%lld",&a[i]);
sort(a,a+m,greater<ll>());
for(int i=0;i<n;i++)
{
scanf("%lld",&b);
ll minn=INT_MAX,jmin=-1;
for(int j=0;j<m;j++)
{
ll tmp=a[j]^b;
bitset<1000> res(tmp);
int t=res.count();
if(t<=minn)
{
minn=t;
jmin=a[j];
}
}
printf("%lld\n",jmin);
}
}
}
return 0;
}
?给出数I,求出大于数I的最小数m,使得m表示成二进制形式时1的个数与I的相等
?考虑极端情形:当数位只有一其余均为0的时候,最小数m只可能为I左移一位的情形。即数m的最大范围为$[m+1,2m]$。故枚举即可。
#include<iostream>
#include<cstdio>
#include<bitset>
using namespace std;
typedef long long ll;
int main()
{
ll q;
while(~scanf("%lld",&q)&&q)
{
bitset<100> s(q);
int t=s.count();
for(int i=q+1;;i++)
{
bitset<100>r(i);
if(r.count()==t)
{
cout<<i<<endl;
break;
}
}
}
return 0;
}
?给出若干集合求可以组成的不同的并集的个数
?状态压缩裸题,将每个集合用二进制数位储存(bitset)并在输入过程中求并。最后统计
#include<bits/stdc++.h>
using namespace std;
int a[1<<15];
int main()
{
int n,m;
while(~scanf("%d %d",&n,&m)&&n&&m)
{
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++)
{
int t;
cin>>t;
bitset<100>q;
for(int i=0;i<t;i++)
{
int tmp;
cin>>tmp;
q[tmp-1]=1;
}
unsigned long res=q.to_ulong();
a[res]=1;
for(int i=0;i<(1<<m);i++)
{
if(a[i])
{
a[i|res]=1;
}
}
}
int cnt=0;
for(int i=0;i<(1<<m);i++)
{
if(a[i]) cnt++;
}
cout<<cnt<<endl;
}
return 0;
}
?黑白棋问题(关灯问题),比较好想的想法是dfs,不太好想的想法是位运算
dfs:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=10;
const int INF=0x3f3f3f;
const int r[5]={-1,0,0, 0,1};
const int c[5]={ 0,1,0,-1,0};
int grid[maxn][maxn];
int ans=INF;
bool judge()
{
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
if(grid[i][j]!=grid[0][0]) return false;
}
}
return true;
}
void flip(int x,int y)
{
for(int i=0;i<5;i++)
{
if(x+r[i]>=0&&x+r[i]<4&&y+c[i]>=0&&y+c[i]<4)
grid[x+r[i]][y+c[i]]=!grid[x+r[i]][y+c[i]];
}
}
void dfs(int x,int y,int t)
{
if(judge())
{
ans=min(ans,t);
return ;
}
if(x>3||y>3||x<0||y<0) return ;
int nx=(x+1)%4;
int ny=y+(x+1)/4;
dfs(nx,ny,t);
flip(x,y);
dfs(nx,ny,t+1);
flip(x,y);
return ;
}
int main()
{
for(int i=0;i<4;i++)
{
for(int j=0;j<4;j++)
{
char tmp;
cin>>tmp;
grid[i][j]=(tmp==‘b‘)?0:1;
}
}
dfs(0,0,0);
if(ans==INF) cout<<"Impossible\n";
else cout<<ans<<endl;
return 0;
}
#include<cstdio>
#include<cstdlib>
using namespace std;
int ans=999999;
int mi[16]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
void search(int x,int f,int st)/*x表当前第几位,f表棋盘状态,st代表翻转次数*/
{
if((f==65535)or(f==0))
{
if(st<ans) ans=st;
return;
}
if(x==17) return;
if(st>=ans) return;
search(x+1,f,st);
f^=(1<<((17-x)-1));//改变自己
if(x%4!=0) f^=(1<<((17-x-1)-1));//改变右边的
if(x%4!=1) f^=(1<<((17-x+1)-1));//改变左边的
if(x>4) f^=(1<<((17-x+4)-1));//改变上面的
if(x<=12) f^=(1<<((17-x-4)-1));//改变下面的
search(x+1,f,st+1);
}
int main()
{
int s=0;
for(int i=1;i<=4;i++)
{
for(int j=1;j<=4;j++)
{
char ch;
scanf("%c",&ch);
if(ch==‘b‘) s+=mi[16-4*i+4-j];/*把矩阵变成一个数,第i位为1代表第(i/4)行第(i%4)(0代表4)列是Black;*/
}
scanf("\n");
}
search(1,s,0);
if (ans==999999) printf("Impossible\n");
else printf("%d\n",ans);
return 0;
}
bfs+位运算
注意C++11结构体的新语法
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<bitset>
#include<stack>
#include<map>
#include<set>
using namespace std;
int n,m,t;
struct node
{
int x,y,t,k;
};
char Map[22][22];
bool vis[22][22][1030];
int dx[]={-1,0,0,1};
int dy[]={0,-1,1,0};
queue<node>Ac;
inline void init()
{
while(Ac.size()) Ac.pop();
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
cin>>Map[i][j];
if(Map[i][j]==‘@‘)
{
Ac.push(node{i,j,0,0});
vis[i][j][0]=1;
}
}
if(i!=n-1) getchar();
}
}
inline void bfs()
{
node now;
while(Ac.size())
{
now=Ac.front();
Ac.pop();
if(Map[now.x][now.y]==‘^‘&&now.t<t)
{
cout<<now.t<<endl;
return ;
}
for(int i=0;i<4;i++)
{
int tx=now.x+dx[i];
int ty=now.y+dy[i];
if(tx<0||ty<0||tx>=n||ty>=m||Map[tx][ty]==‘*‘||vis[tx][ty][now.k]) continue;
if(isupper(Map[tx][ty])&&!(now.k&1<<(Map[tx][ty]-‘A‘))) continue;
int k=now.k;
if(islower(Map[tx][ty]))
{
k=now.k|(1<<(Map[tx][ty]-‘a‘));
}
if(!vis[tx][ty][k])
{
vis[tx][ty][k]=1;
Ac.push(node{tx,ty,now.t+1,k});
}
}
}
puts("-1");
}
int main()
{
while(~scanf("%d%d%d\n",&n,&m,&t))
{
init();
bfs();
}
return 0;
}
八皇后问题,回溯打表或者位运算都要写熟
#include<bits/stdc++.h>
using namespace std;
int a[100],n,ans;
void dfs(int depth)
{
if(depth==n)
{
ans++;
return ;
}
else
{
for(int i=0;i<n;i++)
{
a[depth]=i;
bool flag=true;
for(int j=0;j<depth;j++)
{
if(a[j]==a[depth]||j-a[j]==depth-a[depth]||j+a[j]==depth+a[depth])
{
flag=false;
break;
}
}
if(flag) dfs(depth+1);
}
}
}
int main()
{
while(~scanf("%d",&n)&&n)
{
memset(a,0,sizeof(a));
ans=0;
dfs(0);
cout<<ans<<endl;
}
return 0;
}
位运算:
#include<bits/stdc++.h>
using namespace std;
int lim,sum;
void dfs(int row,int left,int right)
{
if(row==lim)
{
sum++;
return ;
}
else
{
int pos,p;
pos=lim&(~(row|left|right));
while(pos!=0)
{
p=pos&-pos;
pos=pos-p;
dfs(row+p,(left+p)<<1,(right+p)>>1);
}
}
}
int main()
{
int n;
while(~scanf("%d",&n)&&n)
{
sum=0;
lim=(1<<n)-1;
dfs(0,0,0);
cout<<sum<<endl;
}
return 0;
}
1.各种取位技巧,四种基本位运算(与或非异或)
2.快速幂
3.状态压缩与其在dp、搜索中的应用
4.lowbit运算,GCC内置函数
5.bitset的应用
原文:https://www.cnblogs.com/wongdark2017/p/9484606.html