# 2025/6 APCS 實作題 # 第一題 - 小心陷阱 :::info https://zerojudge.tw/ShowProblem?problemid=q836 ::: ## 題目 在一維數線上進行一場模擬遊戲。遊戲規 則如下: 初始位置為0。 初始生命值為k(1 ≤ k ≤ 20)。 當前生命值為v時,角色會往右跳v格,也就是從位置p移動到p + v。 每次移動後,如果落在x1或x2的倍數上,會損失生命值: 若落在x1的倍數,生命值減少y1。 若落在x2的倍數,生命值減少y2。 若同時是x1和x2的倍數,生命值總共減少y1 + y2。 當生命值小於等於 0 時,遊戲結束,輸出當前所在的位置。 ## 輸入說明: 輸入第一行 $k$ 表示初始生命值 第二行有 $x1$ 與 $y1$ 第三行有 $x2$ 與 $y2$ 輸入範圍k:初始生命值, 1 ≤ k ≤ 20 x1、x2:兩個陷阱的倍數條件, 1 ≤ x1, x2 ≤ 10 y1、y2:對應陷阱的扣血值, 1 ≤ y1, y2 ≤ 20 子題 40% : $x1=3, x2=4, y1=y2=k$ 60% : 無額外限制 ## 輸出說明: 輸出遊戲結束所在的位置 ## 解題絲路 ```cpp= ''' 當前生命值為v時,角色會往右跳v格,也就是從位置p移動到p + v。 每次移動後,如果落在x1或x2的倍數上,會損失生命值: 若落在x1的倍數,生命值減少y1。 若落在x2的倍數,生命值減少y2。 若同時是x1和x2的倍數,生命值總共減少y1 + y2。 當生命值小於等於 0 時,遊戲結束,輸出當前所在的位置。 ''' #include <bits/stdc++.h> #define io ios::sync_with_stdio;cin.tie(0); using namespace std; int main(){ io; int k; cin >> k; int x1,y1; cin >> x1>>y1; int x2,y2; cin >> x2>>y2; int tmp=k; int curr=0; while (k>0){ if (tmp%x1==0 && tmp%x2==0){ k-=y1; k-=y2; }else if (tmp%x2==0){ k-=y2; }else if (tmp%x1==0){ k-=y1; } curr=tmp; tmp+=k; } cout <<curr; } ``` --- # 轉盤得分 2025/06 實作第二題 :::info {%preview https://zerojudge.tw/ShowProblem?problemid=q837 %} ::: # 題目 q837. 2. 轉盤得分 - 高中生程式解題系統 你有m個輪盤,每個輪盤上有n格,每格上寫有一個小寫英文字母(a~z)一場遊戲有k個回合。 每個輪盤的轉動可以是正數(順時針)、負數(逆時針)或 0(不轉)。 當所有輪盤都轉動完畢後,觀察它們 對齊位置上的字元。 對於每一個位置(從上到下的每一格),統計出現次數最多的字元,並將該字元的出現次數計 入分數。 每個回合的得分為這n格的對齊統計加總。 最終總得分為所有回合的得分總和。 > 範例 > 一開始有三個輪盤:apcsie, taiwan, icpeda,三個輪盤的轉動距離分別是:1 0 -4 > 結果: > eapcsi ← apcsie 右轉 1 > taiwan ← 不動 > daicpe ← icpeda 左轉 4 分數計算: 第一格: (e, t, d) 出現最多的字元出現 1 次 第二格: (a, a, a) 出現最多的字元出現 3 次 第三格: (p, i, i) 出現最多的字元出現 2 次 第四格: (c, w, c) 出現最多的字元出現 2 次 第五格: (s, a, p) 出現最多的字元出現 1 次 第六格: (i, n, e) 出現最多的字元出現 1 次 這次轉動後的分數是 $10 = 1+3+2+2+1+1$ ## 輸入說明: m n k m 個長度 n 度小寫字母字串 k 行長度 m 的整數陣列表示轉動距離 m, n, k <= 30 -100 <= 轉動距離 <= 100 子題: 60%: m = 3 40%: 無額外限制 ## 輸出說明: 每個回合轉動後的分數總和 ## 解題絲路 這種圓環旋轉,可以用rotate()來快速完成,但rotate只能左旋轉,如何實現右旋轉? :::info 仔細觀察就可以發現左旋轉其實就是n-右旋轉步數 ::: ```cpp= #include <bits/stdc++.h> #define io ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); using namespace std; int main(){io; int m,n,k; cin >> m >> n >> k; vector<string> li(m); for (int i=0;i<m;++i)cin >> li[i]; int ans=0; for (int i=0;i<k;++i){ for (int j=0;j<m;++j){ int mv; cin >> mv; int r; if (mv < 0) { r = abs(mv); r%=n; rotate(li[j].begin(), li[j].begin()+r, li[j].end()); } else if (mv > 0) { r = n-(mv%n); rotate(li[j].begin(), li[j].begin()+r, li[j].end()); } } for (int j=0; j<n; ++j) { array<int,26> cnt = {}; // 0 初始化 for (auto &s : li) { cnt[s[j]-'a']++; } int mx = *max_element(cnt.begin(), cnt.end()); ans += mx; } } cout << ans; return 0; } ``` :::warning 需要注意題目有說旋轉步數會>n,所以要記得%=n,避免溢位 ::: ## 解法2 二維陣列與deque的運用。 題目分兩步驟: 1. 旋轉 2. 計算得分 ### 旋轉 其實就用deque把頭或尾取出,再放到對的地方就好 ### 計算得分 用字典紀錄後再設mx不斷比大小 ```cpp= #include <bits/stdc++.h> #define io ios::sync_with_stdio(0);cin.tie(0) using namespace std; void rotate(int n,deque<char>& q){ if (n<0){ n = abs(n); while (n != 0){ // 左轉(負數) char st = q.front(); q.pop_front(); q.push_back(st); n--; } } else{ while (n != 0){ char st = q.back(); q.pop_back(); q.push_front(st); n--; } } } int count(string& s){ // 尋找最多次字元出現幾次 unordered_map<char,int> um; for (auto i:s){ um[i]++; } int mx=0; for (auto p:um){ mx = max(mx,p.second); } return mx; }; int main(){io; int m=0,n=0,k=0,ans=0; cin >> m >>n>>k; vector<string> li(m); vector<vector<int>> move(k, vector<int>(m));// 宣告二維陣列的語法 for (int i=0; i<m ;++i){ cin >> li[i]; } for (int x=0;x<k;++x){ for (int y=0;y<m;++y){ cin >> move[x][y]; } } // 將 list資料寫進deque vector<deque<char>> Q(m); // queue<string>是錯誤的 for (int a=0;a<m ;++a){ for (auto i: li[a]){ Q[a].push_back(i); } } int c=0,w=0; for (int x=0;x<k;++x){ string s=""; for (int y=0;y<m;++y){ // 執行旋轉的動作 rotate(move[x][y],Q[y]); } for (w=0;w<n;++w){ // 計算此輪分數 for (c=0;c<m;++c){ s+=Q[c][w]; } ans+=count(s); s = ""; } } cout << ans ; return 0; } ``` --- :::info 趁機宣傳一下我自己的個人網站跟Youtube頻道 !! **[個人網站](https://hyc.eshachem.com/) | [Youtube頻道](https://www.youtube.com/@Hy.C)** ::: @2025 Hy.C 陳毓 > Copyright ©Hy.C 陳毓 CC BY-NC-SA 4.0 | 禁止商業用途 | 轉載標記出處 | 改編作品必須在相同條款下分享。