# APCS實作題2025年11月高級第3題:翻來覆去
> 第1版:2025年11月17日
> 第2版:2025年11月24日,更正標題,這題是 APCS **高級**實作題,不是中高級,我之前弄錯了。
> 作者:王一哲
> [ZeroJudge 題目連結](https://zerojudge.tw/ShowProblem?problemid=r628)
<br />
## 解題想法
直接模擬堆疊操作過程一定會超時,要用二元索引樹 (binary indexed tree, BIT, Fenwick Tree) 計算依序移除每個數字時 pop 的次數。以下的寫法還有改進的空間。
<br /><br />
## Python 程式碼
使用時間約為 1.1 s,記憶體約為 19.4 MB,通過測試。
```python=
import sys
class FenwickTree:
""" binary indexed tree """
def __init__(self, n): # 初始化
self.n = n
self.tree = [0]*(n+1) # 必須為 1-indexed
def _lowbit(self, x): # 計算最後一個 1
return x & (-x)
def update(self, i, delta): # 單點更新
while i <= self.n:
self.tree[i] += delta
i += self._lowbit(i)
def query(self, i): # 查詢 i ~ 1 的總和
isum = 0
while i > 0:
isum += self.tree[i]
i -= self._lowbit(i)
return isum
""" 讀取資料 """
n = int(sys.stdin.readline()) # n 個數字
data = list(map(int, sys.stdin.readline().split())) # 讀取數字
pos = [0]*(n+1) # 每個數字在的位置,要改成 1-indexed
for i, d in enumerate(data, start=1):
pos[d] = i
""" 初始化 BIT """
bit = FenwickTree(n)
for i in range(1, n+1): # 每個點的值都設為 1
bit.update(i, 1)
""" 計算 pop 的次數 """
pops, curr = 0, 0 # pop 的次數,目前在的位置
for v in range(1, n+1): # 依序找 1 ~ n
target = pos[v] # 目標數字的位置
if curr == 0: # 第 1 次操作,區間為 [1, target]
left, right = 1, target
else: # 從第 2 次操作開始,區間為 [min(curr, target), max(curr, target)]
left = min(curr, target)
right = max(curr, target)
pops += bit.query(right) - bit.query(left - 1) # 更新 pops
bit.update(target, -1) # bit 之中 target 位置的值歸零
curr = target # 更新 curr 的位置
sys.stdout.write(f"{pops:d}\n")
```
<br />
## C++ 程式碼
使用時間約為 17 ms,記憶體約為 1.1 MB,通過測試。
```cpp=
#include <cstdio>
#include <vector>
#include <algorithm>
typedef long long LL;
using namespace std;
class FenwickTree {
private:
int n;
vector<int> tree;
inline int lowbit(int x) {
return x & (-x);
}
public:
// 建構子,節點數量為 size
FenwickTree(int size) : n(size), tree(size+1, 0) {}
// 單點更新
void update(int i, int delta) {
while(i <= n) {
tree[i] += delta;
i += lowbit(i);
}
}
// 查詢索引值 i ~ 1 的總和
int query(int i) {
int isum = 0;
while(i > 0) {
isum += tree[i];
i -= lowbit(i);
}
return isum;
}
// 查詢索引值 [left, right] 的總和
int range_query(int left, int right) {
if (left >= right) return 0;
return query(right) - query(left - 1);
}
};
int main() {
int n; scanf("%d", &n);
vector<int> pos (n+1);
for(int i=1; i<=n; i++) {
int v; scanf("%d", &v);
pos[v] = i;
}
FenwickTree bit(n);
for(int i=1; i<=n; i++) {
bit.update(i, 1);
}
LL pops = 0;
int curr = 0;
for(int v=1; v<=n; v++) {
int left, right, target = pos[v];
if (curr == 0) {
left = 1;
right = target;
} else {
left = min(curr, target);
right = max(curr, target);
}
pops += bit.range_query(left, right);
bit.update(target, -1);
curr = target;
}
printf("%lld\n", pops);
return 0;
}
```
<br /><br />
---
###### tags:`APCS`、`C++`、`Python`