# APCS實作題2020年7月第3題:圓環出口 > 日期:2024年7月9日 > 作者:王一哲 > [ZeroJudge 題目連結](https://zerojudge.tw/ShowProblem?problemid=f581) ## 題目 ### 問題描述 有 $n$ 個房間排成一個環,編號分別是 $0$ 到 $n-1$。 房間之間有單向的路徑,編號 $i$ 的房間可以走到編號 $(i+1) \% n$ 的房間。 每次進入編號 $i$ 的房間可以獲得 $p_i$ 個點數(最一開始待的房間也可以獲得點數)。 現在依序有 $m$ 個任務,第 $i$ 個任務需要蒐集到 $q_i$ 個點數。對於每次的任務,若一開始在編號 $s$ 的房間,且走到編號 $t$ 的房間時候可以蒐集到需要的點數,則完成這次任務後會停在編號 $(t+1) \% n$ 的房間。 一開始在編號 $0$ 的房間,依據接收到 $m$ 個任務,請求出完成第 $m$ 個任務後會停在哪個編號的房間? <br /> ### 輸入說明 第一行包含兩個正整數 $n, m ~(1 \leq n \leq 200000,~ 1\leq m \leq 20000)$。 第二行包含 $n$ 個正整數 $p_0, p_1, p_2, \dots, p_{n-1}$,$p$ 的總和不超過 $10^9$。 第三行包含 $m$ 個正整數 $q_0, q_1, q_2, \dots, q_{m-1}$,$q_i$ 不會超過 $p$ 的總和。 配分 - 20分:$1 \leq n, m \leq 100$ - 80分:同原題目限制。 <br /> ### 輸出格式 輸出一個非負整數表示最後停在哪個編號的房間 <br /> ### 範例輸入1 ``` 7 3 2 1 5 4 3 5 3 8 9 12 ``` ### 範例輸出1 ``` 4 ``` ### 範例輸入2 ``` 4 3 1 3 5 7 4 2 2 ``` ### 範例輸出2 ``` 0 ``` <br /> ## Python 程式碼 費時最久約為 0.3 s,使用記憶體最多約為 27.4 MB,通過測試。 ```python= from bisect import bisect_left n, m = map(int, input().split()) # 讀取房間數量n、任務數量m ps = list(map(int, input().split())) # 讀取房間的分數 qs = list(map(int, input().split())) # 讀取任務需要的分數 for i in range(1, n): ps[i] += ps[i-1] # 將 ps 改成分數的前綴和 imax = ps[-1] # 所有房間分數總合 base = 0 # 分數基底,前一次任務結束時進入的房間分數總合 head = 0 # 從 qs 讀取資料的索引值 idx = 0 # 任務結束時房間的索引值 while head < m: # 如果 head 還沒有出界時繼續執行 q = qs[head] # 讀取任務分數 q head += 1 # head 加 1 q += base # 更新 q,加上 base idx = bisect_left(ps, q) # 二分搜尋,從 ps 中找 q 的索引值 if idx == n: # 如果沒有找到 q,代表 q 太大 q -= imax # q 減掉 imax,由於題目限制,q <= 2*imax idx = bisect_left(ps, q) # 再找一次 q base = ps[idx] # 更新 base print((idx+1) % n) # 印出答案 ``` 如果 while 迴圈採用以下的寫法,在第3筆測資會出錯,因為第3行 base + q 如果等於 imax,應該會對應到 ps 最後一項,但是先取 %imax 會變成 0。 ```python= while qs: q = qs.pop(0) q = (base + q) % imax idx = bisect_left(ps, q) base = ps[idx] ``` <br /><br /> ## C++ 程式碼 費時最久約為 0.2 s,使用記憶體最多約為 1.2 MB,通過測試。 ```cpp= #include <iostream> #include <algorithm> #include <vector> using namespace std; int main() { int n, m; cin >> n >> m; // 讀取房間數量n、任務數量m vector<int> ps (n, 0), qs (m, 0); for(int i=0; i<n; i++) cin >> ps[i]; // 讀取房間的分數 for(int i=0; i<m; i++) cin >> qs[i]; // 讀取任務需要的分數 for(int i=1; i<n; i++) ps[i] += ps[i-1]; // 將 ps 改成分數的前綴和 int imax = ps[n-1], base = 0, idx = 0, head = 0, q; while(head < m) { // 如果 head 還沒有出界時繼續執行 q = qs[head]; // 讀取任務分數 q head ++; // head 加 1 q += base; // 更新 q,加上 base idx = lower_bound(ps.begin(), ps.end(), q) - ps.begin(); // 二分搜尋,從 ps 中找 q 的索引值 if (idx == n) { // 如果沒有找到 q,代表 q 太大 q -= imax; // q 減掉 imax,由於題目限制,q <= 2*imax idx = lower_bound(ps.begin(), ps.end(), q) - ps.begin(); // 再找一次 q } base = ps[idx]; // 更新 base } cout << (idx+1) % n << "\n"; // 印出答案 return 0; } ``` <br /><br /> --- ###### tags:`APCS`、`Python`、`C++`