自我小整理——位运算

位运算的小整理

备注:以下^符号除程序中均为次方而非异或
1:基础运算符&优先级
加减(+ -)> 移位(<< >>) >比较大小(> < != ==)>位与(&)>异或(cpp ^)>位或(|)
2:memset函数:字节赋值 比如赋值整形 则只能赋值出每8位(2进制位)一样的数(0,0x3f)
3:快速幂:
即将a^b快速计算出的算法 朴素算法下 需要 b次累乘
快速幂 将b写成2进制并分解为(2^ai)形式
由a的(m+n)次方等于a的m次方乘a的n次方 从而进行 log2(b)次累乘解决

#include<iostream>
using namespace std;
long long qsm(long long ,long long ,long long);
int main()
{
 long long a,b,p,ans;
 cin>>a>>b>>p;
 if (b!=0)
 {
  ans=qsm(a,b,p);
  cout<<ans<<endl;
 }
 else cout<<1%p<<endl;
 return 0;
}
long long qsm(long long a,long long b ,long long p)
{
 long long rans, t,i;
 i=a%p;
 rans=1;
 while (b!=0)
 {
  if (b&1) rans=(rans*i)%p;
  i=(i*i)%p;
  b=b>>1;
 }
 return rans;
}

4:与快速幂类似的64位余数乘法算法
直接乘会爆掉 又不想高精度 就把b二进制分解为2^ai
算a*2^ai的和 每次求和

#include<iostream>
using namespace std;
long long wc(long long ,long long ,long long);
int main()
{
 long long a,b,p,ans;
 cin>>a>>b>>p;
 ans=wc(a,b,p);
 cout<<ans<<endl;
 return 0;
}
long long wc(long long a,long long b ,long long p)
{
 long long rans, t,i;
 i=a%p;
 rans=0;
 while (b!=0)
 {
  if (b&1) rans=(rans+i)%p;
  i=(i*2)%p;
  b=b>>1;
 }
 return rans;
}

5:二进制状态压缩
众所周知,一个bool只能表示1 0两个状态,却占用了大量空间!是极大的浪费!相比之下, int类型真是勤俭持家。所以我们不难想到:把长度为n的bool数组转化成0-2^n-1的int, 从而节约时间和空间。
相对应的,为了从转化的int数中直接读取或修改bool数组某项,我们可以用位运算。

操作对应位运算
取出n的2进制第k位:(n>>k)&1
取出n的2进制0-k-1位 :n&(1<<k)
n的2进制第k位取反 :n^(1<<k)
n的2进制第k位赋值1 :n位或(1<<k)
n的2进制第k位赋值1 :n&(~(1<<k))

例子:最短Hamilton路径:
代码:

#include<iostream>
#include<cstring>
using namespace std;
int weigh[30][30];
int f[1<<20][30];
int main()
{
 int i,j,k,n;
 memset(weigh,0,sizeof(weigh));
 memset(f,0x3F,sizeof(f));
 cin>>n;
 for (i=0;i<n;i++)
 for (j=0;j<n;j++)
 {
  cin>>weigh[i][j];
 }
 f[1][0]=0;
 for (i=0;i<1<<n;i++)
 for (j=0;j<n;j++)
 {
  if (i>>j&1)
  {
   for (k=0;k<=n;k++)
   {
    if (((i^1<<j)>>k)&1) 
    if (f[i][j]>f[i^1<<j][k]+weigh[j][k]) f[i][j]=f[i^1<<j][k]+weigh[j][k];
   }
  }
 }
 cout<<f[(1<<n)-1][n-1]<<endl;
 return 0;
}

6:在无向图邻接表创建时存储反向边
2k xor 1=2k+1;
2k+1 xor 1=2k;s
从而实现
7:lowbit运算:用来求n在二进制下最低的位
lowbit(n)=n&(~n+1)=n&(-n)
应用于树状数组
另:结合hash可以求出所有1的位
代码如下

#include<iostream>
#include<cstring>
using namespace std;
int h[1<<20];
int n,i;
int main()
{
 for (i=0;i<=20;i++) 
 {
  h[1<<i]=i;
 }
 while(cin>>n)
 {
  if (n!=0) cout<<h[n&(-n)];
  n=n^n&(-n);
  while (n!=0)
  {
   cout<<" "<<h[n&(-n)];
   n=n^n&(-n);
  }
  cout<<endl;
 }
 return 0;
}

另外 2^i 在0<=i<=35时 有 其模37余数为1——36各不相等 从而可以简单化上述hash

#include<iostream>
#include<cstring>
using namespace std;
int h[100];
long long n,i;
int main()
{
 for (i=0;i<=35;i++) 
 {
  h[(1ll<<i)%37]=i;
 }
 while(cin>>n)
 {
  if (n!=0) cout<<h[(n&(-n))%37];
  n=n^n&(-n);
  while (n!=0)
  {
   cout<<" "<<h[(n&(-n))%37];
   n=n^n&(-n);
  }
  cout<<endl;
 }
 return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值