# 高一基礎程式設計免修上機考
## 前言
因為覺得免修很帥 所以就跑去考了一下
但越接近考試時 越來越緊張 :)
==**這篇主要是給那些學弟想考免修的一些參考ㄏㄏ**==
## 免修資格
1. 要參加高一基礎程式設計的免修需要先有任課老師同意
:::spoiler 當初我與老師的談話
老師 : 你來考免修是學過什麼嗎?
我 : ...(腦袋想了一大堆演算法
老師 : Python?
我 : ㄜ...我上學期上過C++的選修
老師 : ...
我 : ...
(老師簽字)
ps.反正老師一定會給你簽XD
:::
2. 送申請表到教務處的特教組 然後等上機考
3. 上機考通過就免修了
通過條件:五題對四題 也就是==80/100== or ==400/500==分
## 上機考情況
有5個人通過
然後有一個只差5分(幫QQ
[Scoreboard](http://skyoj.tnfsh.tn.edu.tw/sky/index.php/contest/scoreboard/555)

我是==500/500==的 不是沒上 放尊重一點ㄏㄚˋ
## 題目
### **pA**
**題意:**
:::success
**給你 24進制的 $h$小時 $m$分鐘 $s$秒 ex.(19\:45\:34)**
**$h$ $m$ $s$ 為原點的<font color="red">24進位制</font>時間 ( 類似格林威治天文臺**
**再給一個正負時區 $l$ (每一時區$1$ $hour$ $30$ $minutes$)**
**計算這個時區的<font color="red">36進制</font>的時間為何**
**ps. 36進制為小時0~35分鐘、秒數皆60不變**
:::
**~~通靈~~解題思路:**
:::warning
**先將時區的多出或少掉的時間換算成 分鐘**
**然後再用取模的方式算**
:::
:::spoiler **code:**
1. **數學解:)**
```cpp=
#include <iostream>
#include <iomanip> // setw & setfill
using namespace std;
int main() {
int h, m, s, l; cin >> h >> m >> s >> l;
int now = l*3*30; // 每一個l有60min + 30min
m += now%60; // 將m + now取一小時後剩下的餘數 = min
if(m >= 60) { // 如果時區是正數
m -= 60;
h++;
}
if(m < 0) { // 如果時區是負數
m = (m+60)%60;
h--;
}
h = ((h+now/60)%36+36)%36; // 將h + now除上60分鐘 = hour
//偷渡個 setw
cout << h << ":" << setw(2) << setfill('0') << m << ":" << setw(2) << setfill('0') << s << "\n";
}
```
2. **暴力解**
```cpp=
#include <iostream>
#include <iomanip> // setw & setfill
using namespace std;
int main() {
int h, m, s, l;
cin >> h >> m >> s >> l;
if(l > 0) { // 正時區
h += l*1 + l/2;
h %= 36;
m += l%2*30;
if(m >= 60) {h++; m -= 60;}
} else { // 負時區
for(int i = 0; i < abs(l); i++) {
if(m < 30) {
m += 30;
h--;
} else {
m-= 30;
}
h--;
if(h < 0) {h+=36;}
}
}
//偷渡個 setw
cout << h << ":" << setw(2) << setfill('0') << m << ":" << setw(2) << setfill('0') << s << "\n";
}
```
:::
**心得:**
:::danger
**有點棘手的題目**
**考試當下我知道有數學解**
**但當時有點小緊張**
**所以沒那麼冷靜可以去思考**
**(暴力過就好XD**
:::
### **pB**
**題意:**
:::success
**給一原點$(x,y)$ $n$次操作 -> 給你方向$a$ 再給你移動距離$m$**
**求最後的位置 $(x',y')$**
$a=\{1,2,3,4\}$**時** **移動方向為**$\{$上,下,左,右$\}$
:::
**解題思路:**
:::warning
**建表**
**不然就if開個4次 (反正時間很夠XD**
:::
:::spoiler **code:**
**1.建表**
```cpp=
#include <iostream>
using namespace std;
int dx[] = {0, 0, -1, 1};
int dy[] = {1, -1, 0, 0};
int main() {
int x, y; cin >> x >> y;
int n; cin >> n;
for(int i = 0; i < n; i++) {
int a, m; cin >> a >> m;
x += dx[a-1]*m; // 記得a 是1~4但陣列是從0~3
y += dy[a-1]*m;
}
cout << "(" << x << "," << y << ")\n";
}
```
**2.if else 或 switch**
```cpp=
#include <iostream>
using namespace std;
int main() {
int x, y; cin >> x >> y;
int n; cin >> n;
while(n--) {
int a, m; cin >> a >> m;
if(a == 1) {
x += m;
} else if(a == 2) {
x -= m;
} else if(a == 3) {
y -= m;
} else {
y += m;
}
// or
// switch(a) {
// case 1:
// // 懶得寫
// break;
// // 2 , 3, 4
// }
}
cout << "(" << x << "," << y << ")\n";
}
```
:::
**心得:**
:::danger
**學過建表後code會比較簡潔 更容易修改**
:::
**UPD:** **忘記說了 這題範圍到2^31要開<font color = "red" >long long </font>**
### **pC**
**題意:**
:::success
**電梯 上樓時間 $\times3$ 下樓時間 $\times2$**
**一開始在 $1$ 樓**
**搭了$n$次電梯 每次都有一個整數$a$代表去往樓層**
**求總共多少時間**
:::
**解題思路:**
:::warning
**if else 判上下樓 用一個常數維護上一樓**
:::
:::spoiler **code:**
```cpp=
#include <iostream>
using namespace std;
int main() {
int n; cin >> n;
int last = 1; // 一開始在一樓
int ans = 0; // 求多少時間
for(int i = 0; i < n;i++) {
int a; cin >> a;
if(a-last <0) { // 下樓
ans += (last-a)*2;
} else { // 上樓
ans += (a-last)*3;
}
last = a;
}
cout << ans << "\n";
}
```
:::
**心得:**
:::danger
**水題**
:::
### **pD**
**題意:**
:::success
**有一個遙控器 可以轉台 目前在 $a$ 台 想轉到 $b$ 台**
**轉台機制 -> 如果目前頻道是奇數就 $\times 3 +1$ 不是就 $\div2$**
**請問要按幾次按鈕才能到b台**
:::
**解題思路:**
:::warning
**while迴圈**
:::
:::spoiler **code:**
```cpp=
#include <iostream>
using namespace std;
int main() {
int a, b; cin >> a >> b;
ll ans = 0;
while(a != b) {
ans++;
if(a&1) {
a = a*3 + 1;
} else {
a/=2;
}
}
cout << ans << "\n";
}
```
:::
**心得:**
:::success
**一開始以為會TLE 結果水題ㄏㄏ**
**ps. 假如題目給定 a = 0 會TLE喔**
:::
* **pE**
**UPD:**
:::danger
**這題的原型應該是TOI2023新手題的第三題**
**連結**: [zero judge 398](https://zerojudge.tw/ShowProblem?problemid=m398)
:::
**題意:**
:::success
**有 $n$ 個結帳台 每一個都有 $A$ 個客戶且每個客戶都有 $k$ 個商品**
**每結帳一個商品需要花 $3$ 秒 除了第一個課戶以外 其他的客戶需要 $2$ 秒的時間遞補上**
**請問第幾個結帳台所需的時間最小 且為多少秒**
:::
**解題思路:**
:::warning
**用for迴圈紀錄第幾的櫃檯**
**且用數學的角度看每個結帳櫃台需要的時間為 $2\times(a-1) + \Sigma (3\times k_i)$ (所有商品總數x3)**
**最後維護一下答案**
:::
:::spoiler **code:**
```cpp=
#include <iostream>
#include <climits> //INT_MAX
using namespace std;
int main() {
int n; cin >> n;
int mn = INT_MAX, id = -1;
for(int i = 0; i < n; i++) {
int a; cin >> a;
int ans = 2*(a-1);
for(int i = 0; i < a; i++) {
int k; cin >> k;
ans += k*3;
}
if(ans < mn) {
mn = ans;
id = i;
}
}
cout << id+1 << " " << mn << "\n";
}
```
:::
**心得:**
:::danger
**相較之下有水準的題目**
~~**但第一題比較需要想 所以這題還是秒解**~~
:::