【基本算法】位运算

算法竞赛进阶指南题目练习

a^b

acwing

nowcoder

快速幂。

def qpow(base, exp, mod):
    ret = 1
    while exp:
        if exp & 1:
            ret = ret * base % mod
        base = base * base % mod
        exp >>= 1
    return ret


a, b, p = map(int, input().split())
print(qpow(a, b, p) % p)

其实可以直接用 pow 函数。

Raising Modulo Numbers

nowcoder

快速幂。

def qpow(base, exp, mod):
    ret = 1
    while exp:
        if exp & 1:
            ret = ret * base % mod
        base = base * base % mod
        exp >>= 1
    return ret


T = int(input())
for cas in range(T):
    m = int(input())
    n = int(input())
    ans = 0
    for i in range(n):
        x, y = map(int, input().split())
        ans = (ans + qpow(x, y, m)) % m
    print(ans)

64位整数乘法

acwing

nowcoder

出题人希望看到的做法:

a = int(input())
b = int(input())
p = int(input())
ans = 0
while b:
    if b & 1:
        ans = (ans + a) % p
    a = a * 2 % p
    b >>= 1
print(ans)

不讲武德的做法:

a = int(input())
b = int(input())
p = int(input())
print(a * b % p)
#include <bits/stdc++.h>
using namespace std;
using i128 = __int128;
using i64 = long long;
int main(){
    i64 a, b, p;
    cin >> a >> b >> p;
    i128 A = a, B = b, P = p;
    A = A * B % P;
    p = A;
    cout << p << endl;
}

最短Hamilton路径

acwing

nowcoder

状压。\(dp[i][j]\) 表示经过状态 \(i\) 中的点并最后到达 \(j\) 的最短路径。时间复杂度 \(O(n^2 2^n)\)

n = int(input())
adj = []
for _ in range(n):
    adj.append(list(map(int, input().split())))
dp = [[float('inf')] * n for _ in range(1 << n)]
dp[1][0] = 0
for st in range(1 << n):
    for now in range(n):
        if st & (1 << now):
            pre = st - (1 << now)
            for lst in range(n):
                if pre & (1 << lst):
                    dp[st][now] = min(dp[st][now], dp[pre][lst] + adj[lst][now])
print(dp[(1 << n) - 1][n - 1])
#include <bits/stdc++.h>
using namespace std;
int n, a[20][20], dp[1 << 20][20];
int main() {
    cin >> n;
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < n; ++j)
            cin >> a[i][j];
    memset(dp, 0x3f, sizeof(dp));
    dp[1][0] = 0;
    for (int st = 0; st < (1 << n); ++st) {
        for (int now = 0; now < n; ++now) {
            if (st & (1 << now)) {
                int pre = st ^ (1 << now);
                for (int lst = 0; lst < n; ++lst) {
                    if (pre & (1 << lst))
                        dp[st][now] = min(dp[st][now], dp[pre][lst] + a[lst][now]);
                }
            }
        }
    }
    cout << dp[(1 << n) - 1][n - 1] << endl;
    return 0;
}

C++ 4 秒跑完的数据 Python 跑了将近 12 秒。

起床困难综合症

acwing

nowcoder

题面说了一大通废话,其实只是让你从 \([1,m]\) 里选一个数使其经过若干次位运算后的结果最大。

经典的按位拆分的套路,从高位到低位枚举,每一位都尽量最大化贡献。

n, m = map(int,input().split())
tmp = [0, 0xffffffff]
for _ in range(n):
    op, t=input().split()
    t = int(t)
    if op == 'AND':
        tmp[0] &= t
        tmp[1] &= t
    elif op == 'OR':
        tmp[0] |= t
        tmp[1] |= t
    else:
        tmp[0] ^= t
        tmp[1] ^= t
ans = 0
for i in range(30, -1, -1):
    now = 1 << i
    if tmp[0] & now:
        ans += now
    elif tmp[1] & now and now <= m:
        ans += now
        m -= now
print(ans)
posted @ 2021-04-07 23:58  Theophania  阅读(68)  评论(0)    收藏  举报