0x01 基本演算法-位運算
A題:a^b
https://ac.nowcoder.com/acm/contest/996/A
題目描述
求 a 的 b 次方對 p 取模的值,其中 0 <= a,b,p <= 10^9
輸入描述:
三個用空格隔開的整數a,b和p。
輸出描述:
一個整數,表示a^b mod p的值。
例項:
輸入: 2 3 9
輸出: 8
思路:
這道題是要先算出a的b次冪再對其結果進行求模(取餘),因為b最大可為1e+9,按普通做法來做時間複雜度就太大了,顯然這樣過不了題,
能快速算a的b次冪,就能減小時間複雜度,快速冪就是一種不錯的方法。
什麼是快速冪:
快速冪是一種簡化運算底數的n次冪的演算法,理論上其時間複雜度為 O(log₂N),而一般的樸素演算法則需要O(N)的時間複雜度。簡單來說快速冪其實就是抽取了指數中的2的n次冪,將其轉換為時間複雜度為O(1)的二進位制移位運算,所以相應地,時間複雜度降低為O(log₂N)。
程式碼原理:
以 \(a^{13}\) 為例,
先把指數13化為二進位制就是1101,把二進位制數字1101直觀地表現為十進位制則是如下的等式:
\[13 = 1 * (2^3) + 1 * (2^2) + 0 * (2^ 1) + 1 * (2^0) \]
這樣一來 \(a^{13}\) 可以如下算出:
\[a^{13} = a ^ {(2^3)} * a ^ {(2^2)} * a ^ {(2^0)} \]
完整AC程式碼如下:
#include<bits/stdc++.h> using namespace std; typedef long long ll;//將long long型別取個別名:ll型別,為了方便 int power(int a, int b, int mod) { ll ans = 1 % mod; for (; b; b >>= 1) { if (b & 1) ans = ans * a % mod; a = (ll)a * a % mod;//顯式轉化為ll型別進行高精度計算,再隱式轉化為int } return ans; } int main() { //freopen("in.txt", "r", stdin); ios::sync_with_stdio(false), cin.tie(0); int a, b, mod; cin >> a >> b >> mod; cout << power(a, b, mod) << endl; }
C題:64位整數乘法
連結:https://ac.nowcoder.com/acm/contest/996/C
思路:
類似快速冪的思想,把整數b用二進位制表示,即
\[b = c_{k - 1}2^{k - 1} + c_{k -2}2^{k - 2} + ... + c_02^0 \]
#include<bits/stdc++.h> using namespace std; typedef long long ll; int main() { //freopen("in.txt", "r", stdin); ios::sync_with_stdio(false), cin.tie(0); ll a, b, p; cin >> a >> b >> p; ll ans = 0; for (; b; b >>= 1) { if (b & 1)ans = (ans + a) % p; a = (a << 1) % p; } cout << ans << endl; }
D題:最短Hamilton路徑
連結:https://ac.nowcoder.com/acm/contest/996/D
解題思路
AC程式碼:
#include<bits/stdc++.h>
using namespace std;
#define ms(a,b) memset(a,b,sizeof a)
int e[21][21], b[1 << 21][21], n;
int main() {
//freopen("in.txt", "r", stdin);
ios::sync_with_stdio(false), cin.tie(0);
cin >> n;
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
cin >> e[i][j];
ms(b, 0x3f); b[1][0] = 0;
for (int i = 0; i < 1 << n; ++i)
for (int j = 0; j < n; ++j) if (i >> j & 1)
for (int k = 0; k < n; ++k) if (~(i >> k) & 1)//if ((i ^ 1 << j) >> k & 1)
b[i + (1 << k)][k] = min(b[i + (1 << k)][k], b[i][j] + e[j][k]);
cout << b[(1 << n) - 1][n - 1] << endl;
}