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.
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;
}