v0.6.4 - by 晴☆
你需要知道的事
其實就是演算的方法
思考如何更有效率的解決問題
就這樣
蛤?
看個例子大概就知道了
不過先講一下比較實際的東西
可以放學習歷程欸
就是「大學程式設計先修檢測」
應該不用多說什麼了吧
免費的,大家都去考
然後去年的我沒有去考
就是「線上評測系統」
舉個例子:
給高中生的 OJ
是資訊之芽的 OJ
全世界最大的 OJ
有按照難度排序的 OJ
怎麼使用?
不過大部分時候可能都不是正確的
#include <iostream>
int main() {
int a, b;
std::cin >> a >> b;
std::cout << a + b << "\n";
}放一下這題的解答好了
等等 我是特例嗎?
#include <iostream>
int main() {
int a, b;
std::cin >> a >> b;
std::cout << a + b << "\n";
}放一下這題的解答好了
不過大部分時候可能都不是正確的
| 簡稱 | 全名 | 白話的意思 |
|---|---|---|
| AC | Accept | 通過啦~ |
| NA | Not Accept | 沒通過,只拿到部分的分數 |
| WA | Wrong Answer | 錯了,沒分數可以拿 QQ |
| TLE | Time Limit Exceeded | 太慢,超過時間限制 |
| MLE | Memory Limit Exceeded | 使用太多資源,超過記憶體限制 |
| RE | Runtime Error | 執行到一半出現錯誤 |
| CE | Compile Error | 編譯錯誤 |
自己至少執行過一次
測資範圍
要不要開 long long
可不可以用 unsigned
是不是有 0 或 -1 之類的
複雜度
不是啦 這個還沒講
好複雜,我不懂
很多事情
右邊有一些函數的圖形:
\(n\)
\(f(n)\)
感覺很亂,什麼都看不出來?
縮小一點來看!
右邊有一些函數的圖形:
\(n\)
\(f(n)\)
感覺很亂,什麼都看不出來?
縮小一點來看!
\(x! > x^2 > 2x > x > log_2(x)\)
大致看得出速度關係了!
不過要注意一件事
從圖形不能看出真正的關係
比方說:
\(2^{16} x\ 和\ 2^{32} x\\看起來差不多但實際上差很多\)!
演算法的目的是要越有效率越好,以處理更大量的數據
所以,想一個很大的數字當作 \(n\) 吧
以 \(2^{31}\) 為例好了
\(x\ \ \ \ \ \ \ \approx 2.1 \cdot 10^9\)
\(x + 1 \approx 2.1 \cdot 10^9\)
基本上沒什麼差別
所以在複雜度中, \(x + 1 = x\)
演算法的目的是要越有效率越好,以處理更大量的數據
所以,想一個很大的數字當作 \(n\) 吧
以 \(2^{31}\) 為例好了
\(x\ \ \ \ \ \ \ \approx 2.1 \cdot 10^9\)
\(x + 1 \approx 2.1 \cdot 10^9\)
\(\ \ x \approx 2.1 \cdot 10^9\)
\(3x \approx 6.4 \cdot 10^9\)
基本上沒什麼差別
所以在複雜度中, \(x + 1 = x\)
差了 \(3\) 倍欸
\(x^2 \approx 4.6 \cdot 10^{18}\)
差了大概 \( 10^{9}\) 倍!
相較之下 \(3\) 倍似乎不算什麼了
所以在複雜度中, \(3x = x\)
在表示複雜度時把所有常數和係數忽略
\(\Rightarrow O(x^3)\)
要做 \( 8x^3 + 2x^2 + x + log_2(x) + 256 \) 件事
\(\Rightarrow O(x\ log\ x)\)
要做 \( 4x \cdot log_2(x) \) 件事
不是得寸進尺、貪得無厭的感覺啦
有一位製藥機器人 AaW 他可以釀出不同效果的藥水
但今天他一直電別人,導致電力不足,於是今天的藥水品質不一
有的會讓你很有精神,有的會直接讓你昏倒
現在你知道第 \(i\) 杯藥水喝下去會得到的能量為 \(e_i\)
\(\ e_i \in [-128, 128)\)
若你可以選擇要喝哪些,則最多能得到多少能量?
就把能量為正的全都喝掉就好啦
此故事來自 AaW 的簡報
#include <iostream>
#include <vector>
int main() {
// there are n bottles of potion
int n;
std::cin >> n;
// a vector to store the energy content of each potion
std::vector<int> potions;
// input
for (int& p : potions)
std::cin >> p;
// a variable to store the sum of all taken energy
int maxEnergy = 0;
// loop through
for (int& p : potions)
if (p > 0)
maxEnergy += p;
// print the result
std::cout << maxEnergy;
}輸入的順序很重要,不然就會輸入錯的變數
假設這題的順序為 \(n \rightarrow e_1 \rightarrow e_2 \rightarrow e_3 \rightarrow ... \rightarrow e_{n-1} \rightarrow e_n\)
n
e_1 e_2 e_3 e_4 e_5 ... e_n你可能會覺得這樣很噁心
只有一堆數字,都沒有 UI
但沒辦法,我們得要有標準答案,不要太多變化
換成比較好理解的方式會長這樣:
題外話
無論如何都選擇目前看起來比較好的!
以 AaW 的藥水為例,只拿帶正能量的
希望這個作法可以讓最後的結果最好!
但是使用前要先想一想,這個題目真的是要使用貪婪嗎?
使用貪婪的時機:
但基本上沒有人會去證明它
以 AaW 的藥水為例
如果把所有可能都考慮一遍
那就是 \(O(2^n)\)
如果直接貪婪起來
那就是 \(O(n)\)
但我知道拿這個例子來討論複雜度好像沒什麼意義
切一半,然後再切一半
有一天,晴☆在寫程式,但他發現他寫的程式爛掉了
原來是出現了某個 Bug!
不過晴☆有個好習慣,他會把每一個版本都備份
於是就可以回去找這個 Bug 是哪個版本開始出現的
但他發現他目前有 10000 個版本,開始往回翻最多要翻 10000 次
晴☆在找到 Bug 之前可能會先睡著
那我們使用二分搜好了
開始囉!
\(1\)
\(10000\)
Bug 出現
有 Bug
\(5000\)
Step 1
\(1\)
\(10000\)
Bug 出現
沒有 Bug
\(2500\)
Step 2
\(1\)
\(10000\)
Bug 出現
有 Bug
\(3750\)
Step 3
\(1\)
\(10000\)
Bug 出現
沒有 Bug
\(3125\)
Step 4
\(1\)
\(10000\)
Bug 出現
快速地接近目標了!
不過事實上的我是這樣
\(1\)
\(10000\)
Bug 出現
不過事實上的我是這樣
這是需要做最多次的情況之一
從第 10000 個版本開始一個一個往前找
複雜度為 \(O(n)\)
使用二分搜
因為每次都切一半
所以最多只要做 \(log_2(n)\) 次
複雜度為 \(O(log\ n)\)
小寶與小妮又出現了
你加入了某個邪教
今天就是獻祭儀式的日子了
是這樣的,所有人圍成一圈,並編號 \(1 \sim 100\)
接著從 \(1\) 號開始,每個人砍死右手邊的人
然後最後一個人舉刀自殺
儀式開始前,你忽然清醒並發現這是個邪教
但是你是無法退出邪教的
於是你想成為那最後一個人,然後逃走
沒聽懂?畫個圖
你加入了某個邪教
今天就是獻祭儀式的日子了
是這樣的,所有人圍成一圈,並編號 \(1 \sim 100\)
接著從 \(1\) 號開始,每個人砍死右手邊的人
然後最後一個人舉刀自殺
儀式開始前,你忽然清醒並發現這是個邪教
但是你是無法退出邪教的
於是你想成為那最後一個人,然後逃走
沒聽懂?畫個圖
活下來的是 \(3\) 號
今天有 \(100\) 位教徒(包括你自己)
你應該要是第幾號才能最後生存下來並逃走呢?
活下來的是 \(3\) 號