2026 I2P2 TATime

聽說這裡要有一個副標題

Trivia

主要是我怕我忘記講

TA Time

# PRESENTING CODE
  • 每週四的 18:40 開始到我講完,應該會在 1 ~ 1.5 小時上下
  • 主要是講解作業題,偶而(不保證)提一下考試題

Online Judge

# PRESENTING CODE
  • 140.114.85.195
  • 帳號理應創建好了
  • 有修陳煥宗程設一者,帳號沿用
  • 新加入者,帳密都是 ee-class 上的學號
  • 作業出在 Contest 中,無需繳交,但推薦做一下

VSCode & Settings

# PRESENTING CODE
  • Windows:
  • 安裝 VSCode 後,安裝 C/C++ Extension 方便你一鍵編譯
  • 下載 MinGW
  • 把 MinGW 的 bin\ 加入環境變數
  • Mac:
  • 安裝 VSCode 後,安裝 C/C++ Extension 方便你一鍵編譯
  • 在 Terminal 打 xcode-select --install

Compile&Run on Terminal

# PRESENTING CODE
  • 假設現在你寫了一份 duck.c 存在 C:\Users
  • 先用 cd 移動過去,否則 Terminal 讀不到
cd C:\Users
  • 使用 gcc 這個關鍵字來一口氣完成 Preprocess, Complie, Assemble, Linking
  • 然後用 -o 這個 flag 來指定輸出檔
gcc duck.c -o duck
誒 gcc 你拿著 duck.c 去把該做的做一做
最後產生能跑的東西後,命名為 duck 存在原地

Compile&Run on Terminal

# PRESENTING CODE
gcc duck.c -o duck
誒 gcc 你拿著 duck.c 去把該做的做一做
最後產生能跑的東西後,命名為 duck 存在原地
  • Windows 執行檔的副檔名會是 .exe,Mac 則為 .elf
  • 產生完執行檔後,直接打那個執行檔的名稱來 Run,可以省略副檔名
./duck

Compile&Run on Terminal

# PRESENTING CODE
  • 和 -o 相同,這類用減號開頭的關鍵字稱為 flag,用來操控指令細節
Flag意義
-Wall
-Wextra
-Wpedantic

編譯過程中,把遇到且的 warning 印出來
-I告訴系統你的標頭檔可能放在哪裡
-g程式錯誤時,精確輸出來自哪一份檔案的哪一行
-O3套用最極致的效能優化,有機會導致不穩定
-std=c17套用 C17 這個 ISO 語言標準

是不用特別去記,而且這明顯超範圍了

Week.1

2026.09.10

# PRESENTING CODE
  • 給你浮點數 \(x, y\) 與整數 \(z\),輸出 \(x \times y\) 處理到小數點後第 z 位的結果
  • C 的浮點數會有精度問題,float 大概只能撐到小數點後 6~7 位就會失準
  • 通常題目都用 double 就好,他可以撐到小數點後 16 位左右
  • 例如 printf("%.2f", d) 代表"輸出一個叫 d 的 double,處理到小數點後 2 位"
  • 實際上,這個"處理"是四捨六入五成雙
  • printf("%.*f", z, d) :如果你不確定要處理到第幾位,就用 * 佔位
# PRESENTING CODE
  • 然後就照做,堆
#include <stdio.h>

int main (){
	double a, b;
	int z;
	scanf("%lf %lf %d", &a, &b, &z);
	printf("%.*f\n", z, a*b);
}
# PRESENTING CODE
  • 給你兩個浮點數 \(x, y\),輸出他們相乘後處理至小數點後第 4 位的結果
  • 使用 double 可以省去 99% 的煩惱
#include <stdio.h>

int main (){
	double a, b;
	scanf("%lf %lf", &a, &b);
	printf("%.4f", a*b);
}
  • 因為你是用 %.4f,所以它會自動幫你補零!
# PRESENTING CODE
  • 如果你真的想知道,它本來是預期你會這樣寫:
#include <stdio.h>

int main(){
  int a, b, c, d, output;
  scanf("%d.%d %d.%d", &a, &b , &c , &d);
  output = (100*a + b) * (100*c + d); // 全部轉成整數處理
  printf("%d.%04d\n", output/10000, output%10000);
}
  • 整數才會需要寫 "%04d" 來讓它補零到第四位

Week.9

2026.11.04

Mini Project Demo

# PRESENTING CODE
  • 11/10(二)18:40 ~ 22:40,台達 109
  • ee-class 的繳交在 11/09 就截止了喔

About Hackathon

# PRESENTING CODE
  • 11/22 (日)
  • 1~2 個人一組,非常建議找個組員
  • 沒到不會扣分,但到了可以蹭飯兼做出點東西
  • FINAL DEMO DATE:12/22(二)、12/24(四)

C++ Trivial:vector

# PRESENTING CODE
  • 一種長度可以任意變化的陣列,寫題目時比傳統陣列好用有點類似 Python 的 list,宣告方式如下:
# include <bits/stdc++.h> // 這幾乎包含所有你寫題會用到的東西
# include <vector>
/*
 * vector <型態> 命名;
 * vector <型態> 命名(初始大小, 初始值);
 * vector <型態> 命名 = {...};
 */

vector <int> vec_1; // 宣告但不初始化
vector <int> vec_2(10007, -1); // 初始大小 10007,所有人都是 -1
vector <int> vec_3 = {1, 2, 3, 4, 5};
  • 下面兩個 library 二選一:

C++ Trivial:vector

# PRESENTING CODE
  • 重新初始化:使用 .assign()
/*
 * {vector 名稱}.assign(初始大小, 初始值)
 */

vector <int> vec;

int main (){
  int N; cin >> N;
  vec.assign(N+7, -1);
}

C++ Trivial:vector

# PRESENTING CODE
  • 增加元素到最後一格:使用 .push_back()
/*
 * {vector 名稱}.push_back({值})
*/

vector <int> vec = {1, 2, 3, 4, 5};

int main (){
  vec.push_back(6);
  for (int i = 0; i < vec.size(); i++) cout << vec[i] << ' ';
  // 1 2 3 4 5 6
}

C++ Trivial:vector

# PRESENTING CODE
  • 踢掉最後一格的元素:使用 .pop_back()
/*
 * {vector 名稱}.pop_back()
*/

vector <int> vec = {1, 2, 3, 4, 5};

int main (){
  vec.pop_back();
  for (int i = 0; i < vec.size(); i++) cout << vec[i] << ' ';
  // 1 2 3 4
}

C++ Trivial:vector

# PRESENTING CODE
/*
 * .size():得到一個數字,獲取 vector 的大小,裡面沒有元素就是 0
 * .empty():得到一個 bool,代表 vector 是否為空
 * .clear():清空 vector 內所有元素
* */

vector <int> vec(57, 30); // 一個 57 格的 vector,初始值 37
cout << vec.size() << '\n'; // 57

if (vec.empty()) cout << "Nothing inside\n";
else cout << "Elements in vector";

vec.clear();
cout << vec.size() << '\n'; // 0
/*
 * Python:
 * for it in vec:
 * 
 * C++:
 * for (auto it:vec){}
 */

vector <int> vec(57);
for (int i = 0; i < vec.size(); i++) vec[i] = i;
for (auto to:vec) cout << to << ' '; // 0 1 2 3 ... 55 56

存圖!

# PRESENTING CODE
  • 在計算機科學上,我們很喜歡把資訊用圖來表達,具體而言,這本身就叫一種資料結構

1

2

3

4

5

6

7

  • 像右邊的例子,圖通常由兩種元素組成:
  • 點,一般會給他們編號
  • 邊,每條邊連接兩個點
  • 其中,我們非常在乎「能不能從 A 點走到 B 點」這件事
  • 存在從點 1 到點 4 的路徑
  • 不存在從點 1 到點 7 的路徑

存圖!

# PRESENTING CODE
  • 如果要記錄右邊的圖,我們要記錄多少資訊?

1

2

3

4

5

6

7

  • 一共 7 個點(N = 7)
  • 一共 6 條邊(M = 6)
  • 點 1 到點 2 有一條邊
  • 點 1 到點 3 有一條邊
  • 點 1 到點 4 有一條邊
  • 點 2 到點 3 有一條邊
  • 絕大多數的題目,就是用上面的格式給你圖
  • ...

存圖!

# PRESENTING CODE

1

2

3

4

5

6

7

graph[1] = {2, 3, 4}
graph[2] = {1, 3}
graph[3] = {1, 2}
graph[4] = {1, 6}
graph[5] = {7}
graph[6] = {4}
graph[7] = {5}
  • 可以開個二維陣列 graph,索引值是點編號而 graph[x] 中存所有與 x 有邊的點編號
vector <vector <int>> graph;

int main (){
  int N, M; cin >> N >> M;
  graph.resize(N+7); // graph 是 N+7 個空的 vector <int>
  while (M--){ // 開始讀邊
    int a, b; cin >> a >> b; // 假設 a 與 b 之間有邊
    graph[a].push_back(b);
    graph[b].push_back(a);
  }
}

DFS:「有多遠就走多遠,走到不能再走」

# PRESENTING CODE
  • 我們很在乎 A、B 點間有沒有路徑,那最快的方法就是從 A 開始走,試試看能不能走到 B(實作上會用遞迴達成)

4

1

3

2

5

7

6

假設我們現在的位置是 x
下一步我們走訪

與 x 相連,且編號最小的點

DFS:「有多遠就走多遠,走到不能再走」

# PRESENTING CODE
  • 我們很在乎 A、B 點間有沒有路徑,那最快的方法就是從 A 開始走,試試看能不能走到 B(實作上會用遞迴達成)
假設我們現在的位置是 x
下一步我們走訪

與 x 相連,且編號最小的點

Starts from 1

1

3

2

5

7

6

4

DFS:「有多遠就走多遠,走到不能再走」

# PRESENTING CODE
  • 我們很在乎 A、B 點間有沒有路徑,那最快的方法就是從 A 開始走,試試看能不能走到 B(實作上會用遞迴達成)
假設我們現在的位置是 x
下一步我們走訪

與 x 相連,且編號最小的點

Pos:1, Next:2

1

3

2

5

7

6

4

DFS:「有多遠就走多遠,走到不能再走」

# PRESENTING CODE
  • 我們很在乎 A、B 點間有沒有路徑,那最快的方法就是從 A 開始走,試試看能不能走到 B(實作上會用遞迴達成)
假設我們現在的位置是 x
下一步我們走訪

與 x 相連,且編號最小的點

Pos:2, Next:6

1

3

2

5

7

6

4

DFS:「有多遠就走多遠,走到不能再走」

# PRESENTING CODE
  • 我們很在乎 A、B 點間有沒有路徑,那最快的方法就是從 A 開始走,試試看能不能走到 B(實作上會用遞迴達成)
假設我們現在的位置是 x
下一步我們走訪

與 x 相連,且編號最小的點

Pos:6, Next:None

1

3

2

5

7

6

4

DFS:「有多遠就走多遠,走到不能再走」

# PRESENTING CODE
  • 我們很在乎 A、B 點間有沒有路徑,那最快的方法就是從 A 開始走,試試看能不能走到 B(實作上會用遞迴達成)
假設我們現在的位置是 x
下一步我們走訪

與 x 相連,且編號最小的點

Pos:2, Next:None

1

3

2

5

7

6

4

DFS:「有多遠就走多遠,走到不能再走」

# PRESENTING CODE
  • 我們很在乎 A、B 點間有沒有路徑,那最快的方法就是從 A 開始走,試試看能不能走到 B(實作上會用遞迴達成)
假設我們現在的位置是 x
下一步我們走訪

與 x 相連,且編號最小的點

Pos:1, Next:4

1

3

2

5

7

6

4

DFS:「有多遠就走多遠,走到不能再走」

# PRESENTING CODE
  • 我們很在乎 A、B 點間有沒有路徑,那最快的方法就是從 A 開始走,試試看能不能走到 B(實作上會用遞迴達成)
假設我們現在的位置是 x
下一步我們走訪

與 x 相連,且編號最小的點

Pos:4, Next:3

1

3

2

5

7

6

4

DFS:「有多遠就走多遠,走到不能再走」

# PRESENTING CODE
  • 我們很在乎 A、B 點間有沒有路徑,那最快的方法就是從 A 開始走,試試看能不能走到 B(實作上會用遞迴達成)
假設我們現在的位置是 x
下一步我們走訪

與 x 相連,且編號最小的點

Pos:3, Next:5

1

3

2

5

7

6

4

DFS:「有多遠就走多遠,走到不能再走」

# PRESENTING CODE
  • 我們很在乎 A、B 點間有沒有路徑,那最快的方法就是從 A 開始走,試試看能不能走到 B(實作上會用遞迴達成)
假設我們現在的位置是 x
下一步我們走訪

與 x 相連,且編號最小的點

Pos:5, Next:7

1

3

2

5

7

6

4

DFS:「有多遠就走多遠,走到不能再走」

# PRESENTING CODE
  • 我們很在乎 A、B 點間有沒有路徑,那最快的方法就是從 A 開始走,試試看能不能走到 B(實作上會用遞迴達成)
假設我們現在的位置是 x
下一步我們走訪

與 x 相連,且編號最小的點

Pos:7, Next:None

1

3

2

5

7

6

4

DFS:「有多遠就走多遠,走到不能再走」

# PRESENTING CODE
  • 我們很在乎 A、B 點間有沒有路徑,那最快的方法就是從 A 開始走,試試看能不能走到 B(實作上會用遞迴達成)
假設我們現在的位置是 x
下一步我們走訪

與 x 相連,且編號最小的點

Pos:5, Next:None

1

3

2

5

7

6

4

DFS:「有多遠就走多遠,走到不能再走」

# PRESENTING CODE
  • 我們很在乎 A、B 點間有沒有路徑,那最快的方法就是從 A 開始走,試試看能不能走到 B(實作上會用遞迴達成)
假設我們現在的位置是 x
下一步我們走訪

與 x 相連,且編號最小的點

Pos:3, Next:None

1

3

2

5

7

6

4

DFS:「有多遠就走多遠,走到不能再走」

# PRESENTING CODE
  • 我們很在乎 A、B 點間有沒有路徑,那最快的方法就是從 A 開始走,試試看能不能走到 B(實作上會用遞迴達成)
假設我們現在的位置是 x
下一步我們走訪

與 x 相連,且編號最小的點

Pos:4, Next:None

1

3

2

5

7

6

4

DFS:「有多遠就走多遠,走到不能再走」

# PRESENTING CODE
  • 我們很在乎 A、B 點間有沒有路徑,那最快的方法就是從 A 開始走,試試看能不能走到 B(實作上會用遞迴達成)
假設我們現在的位置是 x
下一步我們走訪

與 x 相連,且編號最小的點

Pos:1, Next:None

1

3

2

5

7

6

4

DFS:「有多遠就走多遠,走到不能再走」

# PRESENTING CODE
  • 很明顯,我們需要紀錄每個點有沒有被走過
  • 實際在 DFS 時,我們不會優先選「編號最小的點」,而是誰放在 graph[pos] 的前面,誰就先被走訪
vector <vector <int>> graph; // 假裝它蓋好了
vector <bool> visited;

void dfs (int pos){
  visited[pos] = true;
  for (auto it:graph[pos]){
    if (!visited[it]) dfs(it);
  }
}

int main (){
  int N, M; cin >> N >> M;
  graph.resize(N+7); // 我習慣陣列故意開大一點
  visited.assign(N+7, false); // 一開始所有人都沒被走過
  while (M--){ // 存圖
    int a, b; cin >> a >> b;
    graph[a].push_back(b);
    graph[b].push_back(a);
  }
  
  dfs(1); // 從編號 1 開始盡可能往最遠的地方走
}

DFS:「有多遠就走多遠,走到不能再走」

# PRESENTING CODE
  • 更廣義的 DFS:遞迴式地搜尋,每當你遇到一個可以走的點,就直接走過去,並以他的視角繼續往後走
給你 N 個貓咪吐司的座標,以及一個距離 r
當任兩個貓咪吐司的距離 <= r 時,貓咪吐司就會坍縮成黑洞
問最後場上剩幾個未坍縮的貓咪吐司、幾個黑洞
# PRESENTING CODE
  • pair 類似一個只有兩格的陣列,其中 [0] 稱為 .first,[1] 稱為 .second
# include <bits/stdc++.h>

vector <pair <int, int>> graph;

int main (){
  int N, R; cin >> N >> R;
  vec.assign(N, {0, 0});
  for (int i = 0; i < graph.size(); i++) cin >> graph[i].first >> graph[i].second;
}
pair <int, int> p = {2, 3} // 你可以直接用 {} 來初始化一個 pair
  • 那為何要用 pair <int, int> 存座標?為何不用 vector <int> x(N), y(N)?
  • 在更進階的資結中,可以方便排序
  • 信我,把 x 和 y 分開存很容易出事
# PRESENTING CODE
  • 獲取輸入、存圖
int N, R; 
vector <pair <int, int>> vec; // 每個貓咪吐司的位置
vector <bool> survive; // 紀錄每個貓咪吐司是否健在
int sc, hb;

int main (){
  cin >> N >> R;
  vec.assign(N, {0, 0});
  survive.assign(N+17, true);
  sc = 0; // 剩下的貓咪吐司
  hb = 0; // 黑洞數量
  for (auto &to:vec) cin >> to.F >> to.S; // &to 表示我是用參考下去跑,所以我可以直接修改 to
}
# PRESENTING CODE
  • 我們寫一個 bool dfs(int index),表示我從點 index 下去,對所有與 index 距離 <= R 的點做 DFS
  • 如果 return true,表示我有成功走出任何一步,則把路上所有人的 survive 標記為 false,且黑洞數量 +1
  • 如果 return false,表示我除了點 index 外,沒有成功走出任何一步則 survive[index] = true,貓咪吐司數量 +1
# PRESENTING CODE
  • 我們寫一個 bool dfs(int index),表示我從點 index 下去,對所有與 index 距離 <= R 的點做 DFS
bool dfs(int index, bool ret){
  survive[index] = false; // 先把自己設為 false,避免等等 DFS 出去有人走回來
  int x = vec[index].F, y = vec[index].S;

  for (int i = 0; i < N; i++){
    int nx = vec[i].F, ny = vec[i].S;
    if ((x-nx)*(x-nx) + (y-ny)*(y-ny) <= R*R && survive[i]){
      dfs(i, false); // 只要跑到這行,表示你走出去了
      ret = false;
    }
  }

  if (ret) survive[index] = true; // 如果都沒走出去,再改回來
  return ret;
}
  • 為什麼會有 ret 的設計?當我要從點 index 下去 DFS 時,我可以寫 dfs(index, true),保證只有起點有回傳 true 的能力
# PRESENTING CODE
  • AC Code
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef pair <int, int> pii;
#define F first
#define S second
#define pb push_back

int N, R; 
vector <pii> vec; // 每個貓咪吐司的位置
vector <bool> survive; // 紀錄每個貓咪吐司是否健在
int sc, hb;

bool dfs(int index, bool ret){
  // printf("f, index = %d, ret = %d\n", index, ret);
  survive[index] = false;
  int x = vec[index].F, y = vec[index].S;

  for (int i = 0; i < N; i++){
    int nx = vec[i].F, ny = vec[i].S;
    if ((x-nx)*(x-nx) + (y-ny)*(y-ny) <= R*R && survive[i]){
      dfs(i, false);
      ret = false;
    }
  }

  if (ret) survive[index] = true;
  return ret;
}

int main (){
  cin >> N >> R;
  vec.assign(N, {0, 0});
  survive.assign(N+17, true);
  sc = 0; // 剩下的貓咪吐司
  hb = 0; // 黑洞數量
  for (auto &to:vec) cin >> to.F >> to.S;
  
  for (int i = 0; i < N; i++){
    if (survive[i]){
      if (dfs(i, true)){
        // printf("%d survive\n", i);
        sc++;
      }
      else {
        // printf("%d blackhole\n", i);
        hb++;
      }
    }
  }

  cout << sc << ' ' << hb << '\n';
}

Binary Search

# PRESENTING CODE
  • 如果現在有個 sorted array,裡面的元素從小排到大
  • 你希望知道裡面的其中一個數字 k 的 index 為何,你會怎麼做?
  • 當然,你可以從 index=0 開始慢慢往後比對
2357111417232731
0123456789
34354143444652535657
10111213141516171819

val

index

  • worst case 是 57,你要花 20 筆運算
  • 通常題目的時限是 1s,約能做 \(10^7\) ~ \(10^8\) 筆運算

Binary Search

# PRESENTING CODE
  • 更好的做法:你跟範圍內的中間值 mid 比
2357111417232731
0123456789
34354143444652535657
10111213141516171819

val

index

  • 如果目標比中間值小,代表目標在中間值左邊
  • 如果目標比中間值大,代表目標在中間值右邊
  • 如果目標就是中間值,那你直接找到了
  • worst case:\(log_{2}20 < 5\),最多 5 筆運算就有答案

Binary Search

# PRESENTING CODE
  • 更好的做法:你跟範圍內的中間值 mid 比
  • 如果目標比中間值小,代表目標在中間值左邊
  • 如果目標比中間值大,代表目標在中間值右邊
  • 如果目標就是中間值,那你直接找到了
vector <int> vec = {...};
int l = 0, r = 20;
int tar; cin >> tar; // 假設這是要找的數字

// 假設未探索區間是 [l, r)
while (l < r){
	int mid = (l+r) / 2;
    if (tar <= vec[mid]) r = mid;
    else if (tar > vec[mid]) l = mid+1;
}

cout << l << '\n';

Binary Search

# PRESENTING CODE
  • 為什麼我敢保證 l 一定是答案?
vector <int> vec = {...};
int l = 0, r = 20;
int tar; cin >> tar; // 假設這是要找的數字

// 假設我們要找的區間是 [l, r)
while (l < r){
	int mid = (l+r) / 2;
    if (tar <= vec[mid]) r = mid;
    else if (tar > vec[mid]) l = mid+1;
}

cout << l << '\n';
  • 當 mid 就是答案時,我們選擇讓 r = mid
  • 當 l = r-1 時:如果 l = mid 是答案,那麼 r = mid 迴圈終止

如果 r 是答案,那麼 l = mid+1 = r 迴圈終止

Binary Search

# PRESENTING CODE
  • int lower_bound(vector <int> vec, int t):回傳 sorted array 中第一個 >= t 的值 index
  • int upper_bound(vector <int> vec, int t):回傳 sorted array 中第一個 > t 的值 index
int lb (vector <int> vec, int t){
  int l = 0, r = vec.size();
  while (l < r){
    int mid = (l+r) / 2;
    if (t <= vec[mid]) r = mid;
    else l = mid+1;
  }
  return l;
}
int ub (vector <int> vec, int t){
  int l = 0, r = vec.size();
  while (l < r){
    int mid = (l+r) / 2;
    if (t < vec[mid]) r = mid;
    else l = mid+1;
  }
  return l;
}
# PRESENTING CODE
給你一個數列 a,裡面有很多數字 \(a_1, a_2, ..., a_n\),數字會重複
之後有 Q 筆詢問,每筆訊問輸入一個整數
求這個整數在數列 a 中出現過幾次
  • \(1 \leq a_i \leq 10^9\),題目不可能讓你開那麼大的一維陣列
  • 開一個陣列,用 index 代表數字,value 代表出現次數?
  • 一般而言如果你的陣列大小比 \(10^6\) 大,表示你想錯了
  • 用 std::map 來寫?
  • 完全可以而且很聰明,只是我今天不能教這個
# PRESENTING CODE

1 1 2 2 2 4 5 6 7 7 7 7 7 7 8 12 12 23 45 57 74

聰明的你發現了 upper_bound(7) 不就是紅色那個

聰明的你發現了 lower_bound(7) 不就是藍色那個

  • 所以拿 upper_bound 減掉 lower_bound 就是答案!
  int N; cin >> N;
  vec.assign(N, 0);
  for (auto &to:vec) cin >> to;
  sort(vec.begin(), vec.end());
  int Q; cin >> Q;
  while (Q--){
    int t; cin >> t;
    cout << ub(t)-lb(t) << '\n';
  }
# PRESENTING CODE
  • std::sort()
/*
 * 假設 vector 名稱叫 vec,自行代入
 * sort(vec.begin(), vec.end(), 排序方式)
 * 排序方式你可以填 less<int>() 表示小到大,或 greater<int>() 代表大到小
 * 又或是你自己寫的 comparison function,回傳值是 bool 就好
 */
 
 sort(vec.begin(), vec.end()); // 不寫排序方式的話預設就是小到大
  • std::sort()
# PRESENTING CODE
  • AC Code
#include <bits/stdc++.h>
using namespace std;

#define icisc ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define F first
#define S second
#define pb push_back

vector <int> vec;

int lb (int t){
  int l = 0, r = vec.size();
  while (l < r){
    int mid = (l+r) / 2;
    if (t <= vec[mid]) r = mid;
    else l = mid+1;
  }
  return l;
}

int ub (int t){
  int l = 0, r = vec.size();
  while (l < r){
    int mid = (l+r) / 2;
    if (t < vec[mid]) r = mid;
    else l = mid+1;
  }
  return l;
}

void solve (){
  int N; cin >> N;
  vec.assign(N, 0);
  for (auto &to:vec) cin >> to;
  sort(vec.begin(), vec.end());
  int Q; cin >> Q;
  while (Q--){
    int t; cin >> t;
    cout << ub(t)-lb(t) << '\n';
  }
}

int main (){
  icisc
  bool codeforces = false;
  int N = 1;
  if (codeforces) cin >> N;
  while (N--) solve();
}
# PRESENTING CODE
  • 你要的話也能用 map 來寫
#include <bits/stdc++.h>
using namespace std;

#define icisc ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define F first
#define S second
#define pb push_back

map <int, int> d;

void solve (){
  int N; cin >> N;
  while (N--){
    int tmp; cin >> tmp;
    d[tmp]++;
  }
  int Q; cin >> Q;
  while (Q--){
    int tmp; cin >> tmp;
    cout << d[tmp] << '\n';
  }
}

int main (){
  icisc
  bool codeforces = false;
  int N = 1;
  if (codeforces) cin >> N;
  while (N--) solve();
}

Binary Search

# PRESENTING CODE
  • Binary Search 要繼續往下探討的話還可以講很深,例如能拿來窮舉之類... 你想要的話可以抓這幾題去寫

We'll start at 18:40

cuz TA is hungryyyyyy

Made with Slides.com