【C++】競程筆記(基礎題型)
===
[TOC]
程式碼範例參考:NTUCPC Guide,此筆記僅為個人學習用途。
---
萬用標頭檔
---
`#include <bits/stdc++.h>`
有些OJ不給用要特別注意,能用就用,其他函式庫名稱還是要背一下。還有因為他抓的函式庫比較多的原因,所以執行會變得有點慢,但基本上不影響。
基本輸出輸入優化(提升速度用)
---
`ios::sync_with_stdio(false)`(關閉與C同步的關鍵函式)
`cin.tie(nullptr)`(關閉 flush 機制,若代碼有用到 endl,這條就沒屁用了,要注意)
`endl` 建議用 `\n` 跳脫字元取代。
T 筆測資題型
---
```cpp=
int t;
cin >> t;
while (t--) {
// do something
}
```
`while()` 迴圈,括號裡面如果是 0(false),就停止迴圈。以 `t` 遞減至 0,是比較聰明且簡潔的做法。
此題目會要求輸入 `T` 個測資,並使用迴圈執行 `T` 次讀取。
EOF 處理
---
```cpp=
int n;
while (cin >> n) {
// do something
}
```
`while()` 括號裡面放 `cin >> n`。
EOF:End Of File。
輸入至 0
---
```cpp=
int n;
while (cin >> n && (n != 0)) {
// do something
}
```
`&&` 邏輯運算子 AND,加上 `(n != 0)`,表示輸入至 0 為止結束迴圈。
sstream 函式庫
---
```cpp=
#include <sstream>
```
* istringstream:用於從字串中讀取資料。
* ostringstream:用於將資料寫入字串。
* stringstream:是 istringstream 和 ostringstream 的組合,可以同時進行讀取和寫入。
Tip:stringstream 較為常用。
語法:
```cpp=
#include <sstream>
// 使用 istringstream
std::istringstream iss("some data");
// 使用 ostringstream
std::ostringstream oss;
// 使用 stringstream
std::stringstream ss;
```
這個函式庫是拿來處理字串流的,能將字串當成輸出輸入流來使用。
重點是能拿字串進行數學上的運算。
### 不提供變數數量的題目
---
```cpp=
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main() {
int n = 0, arr[100] = {};
{
string line;
getline(cin, line);
stringstream ss(line);
int x;
while (ss >> x)
arr[++n] = x;
}
}
```
有些題目不會提供變數數量,要自己寫程式判斷,因此就需要 `stringstream` 幫忙。
* `cin`:遇到空格就結束。如:AB CD,只會讀到 AB,不會讀到空格+CD。
* `getline(cin, string)`:string 代表要輸入進去的字串。然後這東西會讀空格(一整行)。
### `cin >> x >>ws` 換行字元問題
---
假設輸入:
```
1
1 2 3 4 5
```
輸入完 1 後,`cin` 不會讀掉換行字元,所以要加上 `cin >> x >> ws;` 去把換行字元讀掉。
`ws` 的意思是使 `cin` 不斷讀掉空白字元直至遇到非空白字元為止。
如果沒加上 `ws`,後續 `getline()` 就讀不到了,因為 `getline()` 會讀到換行字元。
### 非空格字元的輸入
---
假設輸入:
```
1,2,3,4,5,6,7
```
Solution:將逗號去除,改成空格。
```cpp=
for (int i = 0; i < int(str.size()); ++i)
if (str[i] == ',')
str[i] = ' ';
```
Reference 進階應用
---
```cpp=
for (int i = 0; i < n; ++i) {
cal(arr[pl[idx[i]]]);
if (check(arr[pl[idx[i]]]))
arr[pl[idx[i]]] = change(arr[pl[idx[i]]]);
} // 假設 cal, check, change 是三個已經寫好在別處的函式
```
參考(Reference)可說是物件的別名,直接宣告一個變數令 `int &cur = arr[pl[idx[i]]];`,可省去許多麻煩。
```cpp=
for (int i = 0; i < n; ++i) {
int &cur = arr[pl[idx[i]]];
cal(cur);
if (check(cur))
cur = change(cur);
} // 假設 cal, check, change 是三個已經寫好在別處的函式
```
負數取模問題
---
```cpp
(a % b + b) % b
```
-5 / 3 的餘數在 C++ 運算中,會變為 -2,要解決此問題,以上式子即可解決。
邊界檢查(越界存取問題)
---
時常會錯在陣列的索引存取問題,一定要注意陣列索引為 0 ~ n-1(假設陣列長度為 n)。
Tip:若題目範圍上限是 N,則陣列範圍可能取 N + 5,或 N + 10。