位运算

Posted aserrrre

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了位运算相关的知识,希望对你有一定的参考价值。

我一直没有更新,原因不解释。我的luogu有这一篇,我搬运过来哈。

先感谢李煜东老师的辛勤劳动,我是借鉴他的成果。 位运算共有4种,它们是与或非和异或废话

十进制的数不能参与运算,在计算机中是二进制,如果直接对其运算就比十进制块很多。所以说位运算最快,然后是加减,接着是乘除,最慢的是取模,慢的一匹大家先体验一把位运算,打开手机计算器的科学计数法,然后调成二进制。。。

好,与指的是按照二进制位的两个数字,两位都是1就是1,否则为0,或就是按照二进制位两位有一位是1就为1,两个数位都是0才是0,非就是把每一位都取反,异或是两位相同为0,不同为1。需要注意的是两个数比较时不足位按0计算,直到两个数位数相同。

左移就是直接把每一位都向左移,右移也是这样的。随意 来举个例子5等于二进制下的101(这个肯定会啊),左移两位就是10100(低位是0补足),自然是十进制下的20啦!

左移就是乘二右移就是除二,哦我们好像可以用这个优化乘二啊!还有更神奇的事情!n<<1就是乘二,n<<3就是乘8啊,那么加起来不就是乘十了吗?这真是激动人心的发现 当然同理有的减法也可以用^来优化,或可以用来判断奇数:比如11的二进制是1011,(1011&1)=(1011&0001)=(0001)返回了1! 哇太强了,以后可以用(x&1)判断是不是奇数了,如果用x%2的后果就是x不停的减二。。。一直减到剩下1或者0。

顺便讲一下lowbit运算,这个可吊了。lowbit的定义是整数在二进制下最低位的1及其后边的所有0,lowbit(n)=n&(-n) 这波废话其实意思是说找到最右的1构成的数,比如lowbit(14)=1110,那么lowbit(n)就是2啊!这个详见树状数组。

状态压缩就是将一个长度为m的bool数组换成一个用二进制数存贮的方法。下列是状态压缩的常用表达式: 1,取出n的第k位 (n>>k)&1 就是把n删掉几位或1,简单吧

2,取出n的后k位 n&((1<<k)-1) 这个我也不怎么会

3.把n的第k位赋1 n|(1<<k) 就是制造一个数是2的k次方才能和n进行运算啊,同理有 n^(1<<k) 和 n&(~(1<<k))这个是第k位赋0

接下来是位运算实战!!!大佬勿喷

1,位运算加速快速幂

#define int long long
inline int quickpower(int a,int b,int p){
    register int ans=1;
    for (;b;b>>=1){
        if (b&1)    ans=ans*a%p;
        a=a*a%p;
    }return ans;
}

2,最短曼哈顿路径

int f[1<<20][20];
inline int hamilton(int n,int weight[20][20]){
    memset(f,0x3fsizeof(f));
    f[1][0]=0;
    for (register int i=1;i<=1<<n;++i)
    for (register int j=0;j<n;++j)
    if (i<<j&1)
    for (register int k=0;k<n;k++)
    if ((i^1<<j)>>k&1)
    f[i][j]=min(f[i][j],f[i^1<<j][k]+weight[k][j]);
    return f[(1<<n)-1][n-1];
}

我们到了主题,P3901 这道题一开始把我看得一脸懵逼,最后看懂了,原来是要求出是不是每个数字都不同啊!这是我的题解,自然还能优化,不再细说了。


#include<bits/stdc++.h>
using namespace std;
int a[100001],n,q;
bool b[100001];
inline int read(){
    register int x=0;
    register char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c))
    x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x;
}
int main(){register bool flag=false;
    n=read(),q=read();
    for (register int i=1;i<=n;i++)
        a[i]=read();
    for (register int i=1,l,r;i<=q;i++){
        l=read(),r=read(),flag=false;
        memset(b,false,sizeof(b));
        for (register int j=l;j<=r;j++)
            if (b[a[j]]){
                flag=true,puts("No");
                break;
            }
            else    b[a[j]]=1;
        if (!flag)  puts("Yes");
    }
    return 0;
}

以上是关于位运算的主要内容,如果未能解决你的问题,请参考以下文章

编程思想:巧用位运算重构代码

基础位运算基本原理和应用

位运算相关

优雅代码05-从hashMap源码介绍位运算符

c语言位运算问题?

为啥 JSHint 反对位运算符?我应该如何表达这个代码?