← 全部題目
Solved UVa 解題

Mirror Clock

鏡子沿 12–6 點連線左右翻轉,真實時間會是 12:00 扣除鏡中時間;分鐘不為 0 時要借 1 小時,小時算出 ≤ 0 就補 12,因為是 12 小時制。

Attempts3
First attempt2026-09-22
Solved2026-09-22

Problem

小朋友 Onuvob 剛學會看時鐘,而且很愛大聲報時間。他的房間牆上有一個大時鐘,對面剛好有一面鏡子。媽媽發現他有時候會報錯時間,經過一番調查之後才知道,他看時鐘沒問題,問題是他有時候看的是鏡子裡的時鐘 🪞。

媽媽說鏡子裡的時間是錯的,但 Onuvob 卻反問道:「我們可以從鏡子裡的時間算回真的時間,對吧?」

對吧?題目要你來回答,答案確實是可以,而且其實不難。



輸入第一行是測資組數 TT(T<1000T < 1000),接下來 TT 行,每行是鏡中看到的時間,格式是 HH:MM,保證是合法時間。每組輸出一行真實時間,格式一樣是 HH:MM。

老實說這題我壓根沒看題目敘述,只看到了題目名稱、時鐘圖案跟範例測資就知道要幹嘛了。

不過沒看題敘的代價,就是沒注意到這是一個指針時鐘。錶面上只有 1 到 12,沒有 0 點。範例 12:00 → 12:00 其實就在暗示這件事,我的第一版卻會輸出 00:15 這種東西。24 小時制裡它是對的,但題目就真的只是一般的時鐘。

Approach

我一看到範例 10:09 → 01:51 就有想法了:09+51=6009 + 51 = 60, 直覺就是直接拿 60 去扣分鐘,有點像國中學的「互餘」。

後來想想這個直覺其實有道理。鏡子會把時鐘以 12 點和 6 點的連線為軸左右翻轉。指針原本在 12 點順時針轉了 θ\theta 度,鏡子裡看起來就是逆時針轉了 θ\theta 度,也就是順時針 360∘−θ360^\circ - \theta。

換成時間的語言就是一句話:


真實時間=12:00−鏡中時間\text{真實時間} = 12{:}00 - \text{鏡中時間}
鏡中真實說明
03
09
左右對調
06
06
在對稱軸上,不動
12
12
在對稱軸上,一樣不動
10
01
範例,要借位
11
12
算出 0 點 → 要寫成 12
12
11
算出 -1 點 → 要補 12

減法的細節跟小學直式減法一樣,分鐘不夠減就跟小時借 1:

鏡中 10:0912:00 − 10:09分鐘不夠減,借 1 小時11:60 − 10:0901:51 m ≠ 0時 = 11 − h分 = 60 − m

所以分兩種情況:

  • m=0m = 0:時 =12−h= 12 - h,分 =00= 00

  • m≠0m \ne 0:時 =11−h= 11 - h,分 =60−m= 60 - m

最後再把小時拉回 1 到 12:算出來 ≤0\le 0 就 +12+12。


Wrong attempts

第一次 WA:沒想到 0 點

第一版的 m≠0m \ne 0 分支直接輸出 11 - h:

第一版(WA)
} else {
printf("%02d:%02d\n", 11 - h, 60 - m);
}

鏡中 11:45 會算出 11−11=011 - 11 = 0,輸出 00:15,但錶面上沒有 0 點,正確答案是 12:15。一樣是只跑了題目給的範例就送出,而範例剛好沒有碰到這個 case 😂


第二次 WA:只修了 0,沒修到負數

於是我補了一個三元運算,把 0 換成 12:

第二版(WA)
} else {
printf("%02d:%02d\n", 11 - h == 0 ? 12 : 11 - h, 60 - m);
}

還是 WA!?這次我開始自己舉測資,隨便試一個 12:45 就破功了:11−12=−111 - 12 = -1,輸出 -1:45…,時鐘上根本沒有這種東西呀。

把 m≠0m \ne 0 時所有 hh 列出來就一目了然:

鏡中 hh11−h11 - h第二版輸出正確
1 ~ 1010 ~ 1✅✅
11012✅
12-1-1❌ 應為 11

我只處理了 ==0== 0,但 h=12h = 12 時會掉到負數。兩個都是「超出 1 到 12」的同一類問題,應該用 <=0<= 0 一起處理:

第三版的修正
printf("%02d:%02d\n", 11 - h == 0 ? 12 : 11 - h, 60 - m);
printf("%02d:%02d\n", 11 - h <= 0 ? 11 - h + 12 : 11 - h, 60 - m);

0+12=120 + 12 = 12、−1+12=11-1 + 12 = 11,兩個邊界一次解決。


Solution

加上 <=0<= 0 補 12 之後就過了:

main.cc
5 collapsed lines
#include <iostream>
#include <cstdio>
using namespace std;
void solve() {
int t;
int h, m;
while (cin >> t) {
for (int i = 1; i <= t; i++) {
scanf("%d:%d", &h, &m);
if (m == 0) {
if (h == 6 || h == 12) {
printf("%02d:00\n", h);
} else {
printf("%02d:00\n", 12 - h);
}
} else {
printf("%02d:%02d\n", (11 - h <= 0 ? 11 - h + 12 : 11 - h), 60 - m);
}
}
}
}
6 collapsed lines
int main() {
solve();
return 0;
}

標起來的兩段就是全部邏輯:第 14–19 行處理整點,第 21 行處理借位加上拉回 1 到 12。scanf(“%d:%d”) 會把中間的冒號直接吃掉,就不用自己解析字串了。


Sample Input

sample.in
2
12:00
10:09

Sample Output

sample.out
12:00
01:51

驗算:12:00 是整點且 h=12h = 12,原樣輸出;10:09 分鐘不為 0,時 =11−10=1= 11 - 10 = 1、分 =60−9=51= 60 - 9 = 51,得 01:51,答案正確。


錯誤歷程

  1. WA直接輸出 11 - h,只跑了題目給的範例測資#1
  2. WA補了 11 - h == 0 → 12,但漏掉當 h = 12 點時,11 - h = -1#2
  3. AC改成 11 - h <= 0 就 +12,自己多舉了幾個邊界測資就過了#3

See also