---
# System prepended metadata

title: 【C++】競程筆記（基礎題型）
tags: [程式設計, C++, 競程, CP]

---

【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。