关于位运算

0x01 位运算

1. 利用位运算求a^b AcWing 89. a^b

思路:假如b为5,其二进制为(101 = 1*2^0 + 0*2^1 + 1*2^2 = 5),即任意一个整数b均可拆为n个(2^x)的和

(a^x * a^y * a^z = a^{x+y+z}) ,下方base变化过程:(a^{2^0} > a^{2^1} >a^{2^2})

//求a的b次方对p取模
int main() {
    cin >> a >> b >> p;
    long long base = a, res = 1;
    while (b) {
        if (b & 1) res = (base * res) % p;
        base = (base * base) % p;//
        b >>= 1;
    }
    cout << res % p << endl;
    return 0;
}

2. 64位整数乘法 AcWing 90. 64位整数乘法

64位使用unsigned long long (long long 63位 + 1位符号位)

思路: 同上(a*b=a*(2^{x1} + 2^{x2}...))

//求a*b对p取模
typedef unsigned long long ULL;
int main() {
    ULL a, b, p, ans = 0;
    cin >> a >> b >> p;
    while (b) {
        if (b & 1) ans = (ans + a) % p;
        a = (a * 2) % p;
        b >>= 1;
    }
    cout << ans % p << endl;
    return 0;
}

3. 最短Hamilton路径 AcWing 93.

image-20200309113940443

DP状态压缩使用二进制表示一个状态,(f[state][j]) 表示状态为state时,j为停在了哪个点

假设从k点转移过来,则有:(f[state][j]=f[state\_k]+weight[k][j])

const int N = 20, M = 1 << 20;
int n;
int f[M][N], weight[N][N];

int main() {
    cin >> n;
    for (int i = 0; i < n; i++) 
        for (int j = 0; j < n; j++) cin >> weight[i][j]; //读入i到j的距离
    
    memset(f, 0x3f, sizeof f); //sizeof为运算符,非函数,如果不初始化最大,则18行min取最小值,一直为零
    f[1][0] = 0;//当处于起点时 !勿忘初始化
    
    for (int i = 0; i < 1 << n; i++)//从00..(n个0) ~ 11..(n个1) 枚举所有的状态
        for (int j = 0; j < n; j++) //j为停在了哪个点
            if (i >> j & 1)  //如果在i这个状体下,j确实已经到过(即i的第j位为1)
                for (int k = 0; k < n; k++) //从第k个点走到j点
                    if (i - (1 << j) >> k & 1) //判断第k个点是否走过,因为要从k到j说明k要走过
                        f[i][j] = min(f[i][j], f[i - 1 << j][k] + weight[k][j]);//(i - 1 << j)即为在k点未到j点的状态,对于每一个k更新f[i][j]的值,即从0停在j在i的状态下的最小       return 0;
}

原文地址:https://www.cnblogs.com/mayapony/p/12626312.html