【基本算法】位运算
算法竞赛进阶指南题目练习
a^b
快速幂。
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
快速幂。
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位整数乘法
出题人希望看到的做法:
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路径
状压。\(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 秒。
起床困难综合症
题面说了一大通废话,其实只是让你从 \([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)

浙公网安备 33010602011771号