## 迴圈 ### 11/1 社課 ---- 今天會講很多迴圈和串列的題目,所以不熟的話一定要複習前面的內容 --- ## 複習 ---- ### [CSES - Permutations](https://cses.fi/problemset/task/1070) 如果整數 $1, 2, \ldots, n$ 的一個排列中,沒有任何相鄰元素的差為 $1$ ,那麼這個排列稱為漂亮的排列。 給定 $n$,若存在漂亮的排列,請輸出其中一個。 ---- ### [CSES - Permutations](https://cses.fi/problemset/task/1070) - 如果相鄰元素的差不能為 $1$ ,那就考慮相鄰元素的差為 $2$ - 把奇數全部放在一起,偶數也全部放在一起 - 要先放奇數還是偶數? ---- ### [CSES - Permutations](https://cses.fi/problemset/task/1070) - 考慮 $n=4$ - 先放奇數, $1、3、2、4$ 會出問題 - 先放偶數, $2、4、1、3$ 不會出問題 - 先放偶數! ---- ### [CSES - Permutations](https://cses.fi/problemset/task/1070) - $n=2$ 的情況排列只能是 $1、2$ 或 $2、1$ ,無解 - $n=3$ 考慮前兩個數,只能放 $1、3$ 或 $3、1$ - 但最後一個數字只能放 $2$ ,因此也無解 ---- ### [CSES - Permutations](https://cses.fi/problemset/task/1070) - 如果 $n=2$ 或 $n=3$ ,輸出`NO SOLUTION` - 否則先輸出偶數再輸出奇數 ---- ### [CSES - Permutations](https://cses.fi/problemset/task/1070) ```python n = int(input()) if n == 2 or n == 3: print("NO SOLUTION") else: for i in range(2, n + 1, 2): print(i, end = " ") for i in range(1, n + 1, 2): print(i, end = " ") ``` ---- ### [CSES - Trailing Zeros](https://cses.fi/problemset/task/1618) 計算階乘 $n!$ 中後綴零的數量。 ---- ### [CSES - Trailing Zeros](https://cses.fi/problemset/task/1618) - 每個後綴零都來自一對 $2$ 和 $5$ 相乘 - $n!$ 中,因數 $2$ 的數量必定大於因數 $5$ 的數量 - 因數 $5$ 的數量就是後綴零的數量! - 先數 $5^1$ 的倍數數量,再數 $5^2$ 的倍數數量,再數 $5^3$ 的倍數數量,依此類推 ---- ### [CSES - Trailing Zeros](https://cses.fi/problemset/task/1618) ```python n, i, cnt = int(input()), 5, 0 while i <= n: cnt += n // i i *= 5 print(cnt) ``` ---- ### [Zerojudge - 身分證檢驗](https://zerojudge.tw/ShowProblem?problemid=a020) 判斷一個身分證字號是否是正常的號碼。 ---- ### [Zerojudge - 身分證檢驗](https://zerojudge.tw/ShowProblem?problemid=a020) 這是對的,但顯然正常作法不是這樣 ```python s = input() check = 0 if s[0] == 'A': check += 1 elif s[0] == 'B': check += 10 elif s[0] == 'C': check += 19 elif s[0] == 'D': check += 28 elif s[0] == 'E': check += 37 elif s[0] == 'F': check += 46 elif s[0] == 'G': check += 55 elif s[0] == 'H': check += 64 elif s[0] == 'I': check += 39 elif s[0] == 'J': check += 73 elif s[0] == 'K': check += 82 elif s[0] == 'L': check += 2 elif s[0] == 'M': check += 11 elif s[0] == 'N': check += 20 elif s[0] == 'O': check += 48 elif s[0] == 'P': check += 29 elif s[0] == 'Q': check += 38 elif s[0] == 'R': check += 47 elif s[0] == 'S': check += 56 elif s[0] == 'T': check += 65 elif s[0] == 'U': check += 74 elif s[0] == 'V': check += 83 elif s[0] == 'W': check += 21 elif s[0] == 'X': check += 3 elif s[0] == 'Y': check += 12 else: check += 30 for i in range(1, 9): check += (9 - i) * int(s[i]) check += int(s[9]) if check % 10 == 0: print("real") else: print("fake") ``` ---- ### [Zerojudge - 身分證檢驗](https://zerojudge.tw/ShowProblem?problemid=a020) 先介紹 ACSII Code ![image](https://hackmd.io/_uploads/Syl2llW-Jg.png) ---- ### [Zerojudge - 身分證檢驗](https://zerojudge.tw/ShowProblem?problemid=a020) - 在 Python 中可以用 `ord()` 將一個字元轉換成 ACSII Code , `chr()` 將 ACSII Code 轉換成字元 - 把 ACSII Code 當成串列的索引! ---- ### [Zerojudge - 身分證檢驗](https://zerojudge.tw/ShowProblem?problemid=a020) ```python ind = [1, 10, 19, 28, 37, 46, 55, 64, 39, 73, 82, 2, 11, 20, 48, 29, 38, 47, 56, 65, 74, 83, 21, 3, 12, 30] s = input() check = 0 check += ind[ord(s[0]) - ord('A')] for i in range(1, 9): check += (9 - i) * int(s[i]) check += int(s[9]) if check % 10 == 0: print("real") else: print("fake") ``` ---- ### 練習 Zerojudge - 四則運算 --- ## stack ---- ### stack - 後入先出 (LIFO, Last In, First Out) 的資料結構 - 後加入stack的元素會先被移除 ---- ### stack ![image](https://hackmd.io/_uploads/Hkl3JLX4C.png) ---- ### stack - Python 的串列有`append()`、`pop()` - 串列其實可以當做 stack 用 ---- ### [Zerojudge - stack 練習](https://zerojudge.tw/ShowProblem?problemid=i213) ```python n = int(input()) stack = [] for i in range(n): e = input() if e.startswith("1"): _, x = e.split() stack.append(x) elif e.startswith("2"): if stack: print(stack[-1]) else: print(-1) else: if stack: stack.pop() ``` ---- ### [Zerojudge - Rails](https://zerojudge.tw/ShowProblem?problemid=c123) 有一個車站,火車從右邊來、從左邊離開。判斷火車能否以一特定的排列方式在左邊的鐵軌上。 ---- ### [Zerojudge - Rails](https://zerojudge.tw/ShowProblem?problemid=c123) - 車站就是一個 stack - 直接模擬 ---- ### [Zerojudge - Rails](https://zerojudge.tw/ShowProblem?problemid=c123) ```python while True: n = int(input()) if n == 0: break while True: a = list(map(int, input().split())) if a[0] == 0: break cur = 0 stack = [] for i in range(1, n + 1): stack.append(i) while stack and stack[-1] == a[cur]: stack.pop() cur += 1 if not stack: print("Yes") else: print("No") print() ``` ---- ### [CSES - Nearest Smaller Values](https://cses.fi/problemset/task/1645) 給定一個包含 $n$ 個整數的陣列,對於每個整數,找到其左側最近的較小值所在的位置,如果沒有則輸出 $0$ ---- ### [CSES - Nearest Smaller Values](https://cses.fi/problemset/task/1645) - 如果每一次都往左檢查直到找到較小值會太慢 - 可以觀察到在陣列中的任兩個數字,若左邊的數字大於右邊的數字,那麼右邊的數字以後的所有數字都不會以左邊的數字為答案 ---- ### [CSES - Nearest Smaller Values](https://cses.fi/problemset/task/1645) ![image](https://hackmd.io/_uploads/rJUEJj4V0.png) ---- ### [CSES - Nearest Smaller Values](https://cses.fi/problemset/task/1645) - 可以維護一個隊列,在一個數加入隊列前把所有大於等於該數的數字全部都刪除 - 得到答案後再把這個數加入隊列中,可以發現因為加入的數必定大於隊列裡面所有的數,因此這個隊列必定是遞增的,因此這個技巧被稱為「單調」隊列 ---- ### [CSES - Nearest Smaller Values](https://cses.fi/problemset/task/1645) - 因為隊列是遞增的,所以在插入一個數字前做刪除操作時只會從隊列的最後開始更改,插入數字時也是放到數字最尾端 - 可以用 stack 來實作,並維護其內容單調遞增 - 實作上要注意因為要輸出的是「位置」而不是「值」,因此在隊列中直接存元素所在的位置會方便許多,而隊列維護的內容為「其對應的值呈單調遞增」 ---- ### [CSES - Nearest Smaller Values](https://cses.fi/problemset/task/1645) ```python n = int(input()) a = list(map(int, input().split())) stack = [] for i in range(n): while stack and a[stack[-1]] >= a[i]: stack.pop() if stack: print(stack[-1] + 1, end = " ") else: print(0, end = " ") stack.append(i) ``` ---- ### 練習 [Zerojudge - 最大矩形](https://zerojudge.tw/ShowProblem?problemid=b123) ---- ### [Zerojudge - 最大矩形](https://zerojudge.tw/ShowProblem?problemid=b123) ``` while True: try: m, n = map(int, input().split()) a = [] mx = 0 for i in range(m): a.append(list(map(int, input().split()))) for i in range(1, m): for j in range(n): if a[i][j] == 1: a[i][j] += a[i - 1][j] for i in range(m): lmin, rmin, sl, sr = [-1] * n, [n] * n, [], [] for j in range(n): while sl and a[i][sl[-1]] >= a[i][j]: sl.pop() if sl: lmin[j] = sl[-1] sl.append(j) for j in range(n - 1, -1, -1): while sr and a[i][sr[-1]] >= a[i][j]: sr.pop() if sr: rmin[j] = sr[-1] sr.append(j) for j in range(n): mx = max(mx, (rmin[j] - lmin[j] - 1) * a[i][j]); print(mx) except: break ```
{"title":"迴圈","contributors":"[{\"id\":\"3aeed4e7-1118-47e7-b0cc-18caea236427\",\"add\":8704,\"del\":412}]","description":"結果"}
    104 views