熱門文章

2026年4月17日 星期五

ZeroJudge 解題筆記:d131. 00160 - Factors and Factorials

作者:王一哲
日期:2026年4月17日


ZeroJudge 題目連結:d131. 00160 - Factors and Factorials

解題想法


題目要計算 $1!$ 到 $100!$ 每個數字之中,所有相乘的質數次方。可以先建 $1$ 到 $100$ 之間的質數表 $primes$。接下來用一個長度為 $101$ 的串列 $dp$,儲存 $1!$ 到 $100!$ 對應的答案,用字典格式儲存,key 為質數,value 為次方。由於 $i! = i \times (i-1)!$ ,更新 $dp[i]$ 時先複製 $dp[i-1]$ 的資料,再加上 $i$ 的質因數分解結果。最後再依序讀取測資,從 $dp$ 之中找對應的答案,排列成題目要求的格式並輸出。

Python 程式碼


使用時間約為 8 ms,記憶體約為 8.8 MB,通過測試。
def solve():
    import sys
    
    """ 1 ~ 100 之間的質數 """
    maxn = 100
    sieve = [True]*(maxn+1)
    sieve[0] = sieve[1] = False
    for i in range(2, int(maxn**0.5) + 1):
        if sieve[i]:
            for j in range(i*i, maxn+1, i):
                sieve[j] = False
    primes = [i for i in range(101) if sieve[i]]
    
    """ 建表,dp 的內容是 0 ~ 100 每個質因數對應的次方,字典格式 """
    dp = [{p:0 for p in primes} for _ in range(maxn+1)]
    for i in range(2, maxn+1):  # 依序測試 2 ~ 100
        dp[i] = dp[i-1].copy()  # 複製前一組的資料
        x = i  # 暫存 i 的值
        for p in primes:  # 依序讀取質數
            y = 0  # 要增加的次方
            while x%p == 0:  # 如果 p 可以整除 x
                y += 1  # y 加 1
                x //= p  # x 除以 p
            if y > 0:  # 如果 y 大於 0
                dp[i][p] += y  # 更新 dp[i][p] 對應的次方
            if x == 1: break  # 如果 x 等於 1,不需要再測試

    """ 讀取資料,從 dp 讀取質因數的次方,組合成答案 """
    result= []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        n = int(data[ptr])
        ptr += 1
        if n == 0: break
        cofs = list(dp[n].values())  # 取出各個質因數的次方組成 list
        while cofs[-1] == 0: cofs.pop()  # 移除最後面的 0
        res = f"{n:3d}! ="  # 答案的開頭
        for i, cof in enumerate(cofs, start=1):  # 依序讀取 cofs
            res += f"{cof:3d}"  # 每個次方佔 3 格
            if i%15 == 0 and i < len(cofs): res += "\n      "  # 每 15 個要換行並空 6 格,如果是最後一項不換行
        res += "\n"  # 最後再換行
        result.append(res)
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()


2026年4月16日 星期四

ZeroJudge 解題筆記:d129. 00136 - Ugly Numbers

作者:王一哲
日期:2026年4月16日


ZeroJudge 題目連結:d129. 00136 - Ugly Numbers

解題想法


將找到的 ugly number 存入串列 $ugly$ 之中,再用 3 個變數 $i, j, k$ 分別儲存目前串列之中最後一個 $2, 3, 5$ 的倍數索引值。用 while 迴圈,執行到串列的長度等於 1500 為止,裡面再用 3 個 while 迴圈,更新 $i, j, k$ 的值,更新完之後再取 $ugly[i]*2, ugly[j]*3, ugly[k]*5$ 的最小值,就是新的 ugly number。

Python 程式碼


使用時間約為 7 ms,記憶體約為 8.4 MB,通過測試。
ugly = [1]
i, j, k = 0, 0, 0  # 2, 3, 5 的倍數在 ugly 之中的索引值
while len(ugly) < 1500:
    # 更新 i, j, k,直到對應的數位分別乘以 2, 3, 5 大於 ugly 最後一項為止
    while ugly[i]*2 <= ugly[-1]: i += 1
    while ugly[j]*3 <= ugly[-1]: j += 1
    while ugly[k]*5 <= ugly[-1]: k += 1
    ugly.append(min(ugly[i]*2, ugly[j]*3, ugly[k]*5))  # 取最小一項加到 ugly
print(f"The 1500'th ugly number is {ugly[-1]:d}.")


2026年4月15日 星期三

ZeroJudge 解題筆記:d121. 00583 - Prime Factors

作者:王一哲
日期:2026年4月15日


ZeroJudge 題目連結:d121. 00583 - Prime Factors

解題想法


因為 $n$ 的上限為 $2^{31}$,質因數的上限為 $\sqrt{2^{31}} \approx 46340$,可以先建 $1$ 到 $46340$ 的質數表,然後再用試除法找質因數。不過這題最麻煩的地方,反而是在於要拼出正確的輸出格式。

Python 程式碼


使用時間約為 39 ms,記憶體約為 9.1 MB,通過測試。
def solve():
    import sys
    
    # 建質數表,1 ~ sqrt(2^31),大約 46340
    maxn = 46340
    sieve = [True]*(maxn + 1)
    sieve[0] = sieve[1] = False
    for i in range(2, int(maxn**0.5) + 1):
        if sieve[i]:
            for j in range(i*i, maxn + 1, i):
                sieve[j] = False
    primes = [i for i in range(maxn + 1) if sieve[i]]
    
    # 主要的解題過程
    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        n = int(data[ptr])
        ptr += 1
        if n == 0: break  # 停止運作的條件
        if n == 1:  # 特例
            result.append("1 = 1\n")
            continue
        factors = []  # 質因數
        m = n  # n 的質先存到 m
        if m < 0:  # 負數
            factors.append(-1)  # 先加入 -1
            m = -m  # 轉為正值
        # 找質因數,m 的值先存到 x
        x = m
        for p in primes:
            if p*p > x:  # 沒有更大的質因數,中止迴圈
                break
            while x%p == 0:
                factors.append(p)
                x //= p
        if x > 1: factors.append(x)
        # 組合答案
        res = " x ".join(map(str, factors))
        result.append(f"{n:d} = {res}\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()


2026年4月14日 星期二

ZeroJudge 解題筆記:d120. 10699 - Count the factors

作者:王一哲
日期:2026年4月14日


ZeroJudge 題目連結:d120. 10699 - Count the factors

解題想法


這題可以事先計算 1 到 1000000 對應的最小質因數,在找特定數字 $n$ 的質因數個數時會比較快,可以從目前的值跳到下一個質因數。如果直接用除的,逐一測試比目前數值 $x$ 還小的質因數,這樣也會過,只是速度慢一點。

Python 程式碼


使用時間約為 87 ms,記憶體約為 18.4 MB,通過測試。
def solve():
    import sys

    # 建表,1 ~ 1000000 之間每個數對應的最小質因數 smallest prime factor
    max_num = 1000000
    spf = [0]*(max_num + 1)
    for i in range(2, max_num + 1):
        if spf[i] == 0:  # i 是質數
            spf[i] = i
            if i*i <= max_num:
                for j in range(i*i, max_num + 1, i):
                    if spf[j] == 0:  # 如果 j 還沒有最小質因數,設定成 i
                        spf[j] = i
    # 主要的解題過程
    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        n = int(data[ptr])
        ptr += 1
        if n == 0: break  # 停止的條件
        if n == 1:  # 特例
            result.append("1 : 0\n")
            continue
        cnt = 0  # 質因數數量
        x = n  # n 的值存到 x
        while x > 1:  # 如果 x 還能分解繼續執行
            p = spf[x]  # 取出 x 的最小質因數
            cnt += 1
            while x%p == 0:  # 如果 p 可以整除 x 繼續執行
                x //= p  # x 除以 p
        result.append(f"{n:d} : {cnt:d}\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()

2026年4月13日 星期一

ZeroJudge 解題筆記:d117. 10924 - Prime Words

作者:王一哲
日期:2026年4月13日


ZeroJudge 題目連結:d117. 10924 - Prime Words

解題想法


因為題目的字元編號最大值為 $52$,字串長度最大值為 $20$,因此只要建 $0$ 到 $1040$ 之間的質數表就可以了。需要注意,這題的 $1$ 被當作質數,因為範例測資中的 a 答案為 "It is a prime word."。接下來讀取字串,計算各字元的編號加總,查質數表,輸出對應的答案。

Python 程式碼


使用時間約為 7 ms,記憶體約為 8.4 MB,通過測試。
def solve():
    import sys

    maxn = 1040
    sieve = [True]*(maxn+1)
    sieve[0] = False
    for i in range(2, int(maxn**0.5) + 1):
        if sieve[i]:
            for j in range(i*i, maxn+1, i):
                sieve[j] = False
    
    result = []
    data = sys.stdin.read().split()
    ptr = 0
    while ptr < len(data):
        s = data[ptr]
        ptr += 1
        total = 0
        for c in s:
            if c.isupper():
                total += ord(c) - ord('A') + 27
            elif c.islower():
                total += ord(c) - ord('a') + 1
        result.append("It is a prime word.\n" if sieve[total] else "It is not a prime word.\n")
    sys.stdout.write("".join(result))

if __name__ == "__main__":
    solve()


2026年4月12日 星期日

ZeroJudge 解題筆記:d111. 10110 - Light, more light

作者:王一哲
日期:2026年4月12日


ZeroJudge 題目連結:d111. 10110 - Light, more light

解題想法


這題考數學。第 $1$ 趟及第 $n$ 趟都會改變第 $n$ 盞燈的開關,效果抵消。只要找第 $2$ 趟到第 $(n-1)$ 趟之間改變第 $n$ 盞燈的開關次數 $cnt$,也就是找因數的數量,如果 $cnt$ 是奇數輸出 $yes$,反之輸出 $no$。可以用 for 迴圈找 $i = 2$ 到 $i = \sqrt{n}$ 之間有幾個 $n$ 的因數,如果 $i^2 \neq n$ 增加 $2$ 個因數,如果 $i^2 = n$ 增加 $1$ 個因數。所以這題可以直接用 $n$ 是否為完全平方數找答案。

Python 程式碼


找 $n$ 的因數數量,使用時間約為 14 ms,記憶體約為 8.1 MB,通過測試。
import sys

result = []
for line in sys.stdin:
    n = int(line)
    if n == 0: break
    factors = {1, n}
    for i in range(2, int(n**0.5)+1):
        if n%i == 0:
            factors.add(i)
            factors.add(n//i)
    result.append("yes\n" if len(factors)%2 == 1 else "no\n")
sys.stdout.write("".join(result))

檢查 $n$ 是否為完全平方數,使用時間約為 7 ms,記憶體約為 8.2 MB,通過測試。
import sys

result = []
for line in sys.stdin:
    n = int(line)
    if n == 0: break
    r = int(n**0.5)
    result.append("yes\n" if r*r == n else "no\n")
sys.stdout.write("".join(result))


2026年4月11日 星期六

ZeroJudge 解題筆記:d096. 00913 - Joana and the Odd Numbers

作者:王一哲
日期:2026年4月11日


ZeroJudge 題目連結:d096. 00913 - Joana and the Odd Numbers

解題想法


這題考數學。假設最後一項有 $n$ 項,則題目問的是第 $i$ 列($i = \frac{n+1}{2}$),此列最後一項 $$ a = \frac{[1 + 1 + 2 \times(i-1)] \times i}{2} $$ 最後 $3$ 項相加為 $(2a -1) \times 3 - 6$。 這題的測資 $n$ 有點大,用 C++ 解題時用 int 會溢位。

Python 程式碼


使用時間約為 7 ms,記憶體約為 8.4 MB,通過測試。
import sys

result = []
for line in sys.stdin:
    n = int(line)  # 最後一列有 n 項
    i = (n+1) // 2  # 第 i 列
    a = (1 + 1 + 2*(i-1)) * i // 2  # 第 i 列的最後 1 項
    result.append(f"{(a*2 - 1)*3 - 6:d}\n")  # 第 i 列最後 3 項相加
sys.stdout.write("".join(result))


2026年4月10日 星期五

ZeroJudge 解題筆記:d095. 00579 - ClockHands

作者:王一哲
日期:2026年4月10日


ZeroJudge 題目連結:d095. 00579 - ClockHands

解題想法


先計算時針與12點的夾角,由於時針每12小時轉360度,1小時轉30度,1分鐘轉0.5度,計算角度前先將小時 h 對 12 取餘數。再計算分針與12點的夾角,分針每60分鐘轉360時,1分鐘轉6度。再將兩個角度相減、取絕對值,如果絕對值大於180度,再將答案改成360度減掉絕對值。

Python 程式碼


使用時間約為 7 ms,記憶體約為 8.2 MB,通過測試。
import sys

result = []
for line in sys.stdin:
    if line.strip() == "0:00": break
    h, m = map(int, line.split(":"))
    a = h%12*30 + m/2
    b = m*6
    c = abs(a-b)
    if c > 180: c = 360 - c
    result.append(f"{c:.3f}\n")
sys.stdout.write("".join(result))


2026年4月9日 星期四

ZeroJudge 解題筆記:d094. 00478 - Points in Figures: Rectangles and Circles, and Triangles

作者:王一哲
日期:2026年4月9日


ZeroJudge 題目連結:d094. 00478 - Points in Figures: Rectangles and Circles, and Triangles

解題想法


這題是 d093. 00477 - Points in Figures: Rectangles and Circles 的加強版,除了長方形、圓形之外還多了三角形,可以用上一題的程式碼為基礎,再加上檢查點是否在三角形內的自訂函式。 假設平面上的三角形 ABC 頂點座標分別為 $(x_A, y_A), (x_B, y_B), (x_C, y_C)$,如果要判斷平面上的點 P $(x_P, y_P)$ 是否在三角形之中,P 點座標可以表示為 $$ P = uA + vB + wC $$ 解聯立後可得 $$ \begin{align*} u &= \frac{(x_B - x_A)(y_P - y_A) - (y_B - y_A)(x_P - x_A)}{(x_B - x_A)(y_C - y_A) - (y_B - y_A)(x_C - x_A)}\\ v &= \frac{(x_C - x_A)(y_P - y_A) - (y_C - y_A)(x_P - x_A)}{(x_C - x_A)(y_B - y_A) - (y_C - y_A)(x_B - x_A)} \\ w &= 1 - u - v & \end{align*} $$ 係數符合的條件為
  • $0 \leq u \leq 1$
  • $0 \leq v \leq 1$
  • $0 \leq w \leq 1$


Python 程式碼


使用時間約為 9 ms,記憶體約為 8.6 MB,通過測試。
import sys

def in_rectangle(x, y, x1, y1, x2, y2):
    """
    代入要測試的點座標 (x, y)
    長方形左上頂點座標 (x1, y1)
    長方形右下頂點座標 (x2, y2)
    判斷點是否在長方形內
    """
    if x1 < x < x2 and y1 > y > y2: return True
    return False

def in_circle(x, y, xc, yc, r):
    """
    代入要測試的點座標 (x, y)
    圓心座標 (xc, yc)、半徑 r
    判斷點是否在圓形內
    """
    if (x-xc)**2 + (y-yc)**2 < r**2: return True
    return False

def in_triangle(x, y, xA, yA, xB, yB, xC, yC):
    """
    代入要測試的點座標 (x, y)
    三角形頂點座標 (xA, yA), (xB, yB), (xC, yC)
    判斷點是否在三角形內
    """
    u = ((xB - xA)*(y - yA) - (yB - yA)*(x - xA)) / ((xB - xA)*(yC - yA) - (yB - yA)*(xC - xA))
    v = ((xC - xA)*(y - yA) - (yC - yA)*(x - xA)) / ((xC - xA)*(yB - yA) - (yC - yA)*(xB - xA))
    w = 1 - u - v
    if 0 <= u <= 1 and 0 <= v <= 1 and 0 <= w <= 1: return True
    return False

""" 讀取形狀 """
figures = [[]]
for line in sys.stdin:
    if line.strip() == "*": break
    data = line.split()
    if data[0] == "r":
        figures.append([0] + list(map(float, data[1:])))
    elif data[0] == "c":
        figures.append([1] + list(map(float, data[1:])))
    else:
        figures.append([2] + list(map(float, data[1:])))

""" 判斷點是否在圖形內並組合答案 """
result = []
i = 0
n = len(figures)
for line in sys.stdin:
    if line.strip() == "9999.9 9999.9": break
    i += 1
    state = False
    x, y = map(float, line.split())
    for j in range(1, n):
        if figures[j][0] == 0:
            if in_rectangle(x, y, figures[j][1], figures[j][2], figures[j][3], figures[j][4]):
                result.append(f"Point {i:d} is contained in figure {j:d}\n")
                state = True
        elif figures[j][0] == 1:
            if in_circle(x, y, figures[j][1], figures[j][2], figures[j][3]):
                result.append(f"Point {i:d} is contained in figure {j:d}\n")
                state = True
        else:
            if in_triangle(x, y, figures[j][1], figures[j][2], figures[j][3], figures[j][4], figures[j][5], figures[j][6]):
                result.append(f"Point {i:d} is contained in figure {j:d}\n")
                state = True
    if not state:
        result.append(f"Point {i:d} is not contained in any figure\n")
sys.stdout.write("".join(result))


2026年4月8日 星期三

ZeroJudge 解題筆記:d093. 00477 - Points in Figures: Rectangles and Circles

作者:王一哲
日期:2026年4月8日


ZeroJudge 題目連結:d093. 00477 - Points in Figures: Rectangles and Circles

解題想法


另外寫兩個自訂函式 in_rectangle 及 in_circle,分別用來檢查指定的座標是否在長方形或圓形之中。先儲存所有形狀的資料,讀取到檢查的點之後,依序檢查這個點在哪些編號的圖形之中並輸出答案。

Python 程式碼


使用時間約為 9 ms,記憶體約為 8.5 MB,通過測試。
import sys

def in_rectangle(x, y, x1, y1, x2, y2):
    """
    代入要測試的點座標 (x, y)
    長方形左上頂點座標 (x1, y1)
    長方形右下頂點座標 (x2, y2)
    判斷點是否在長方形內
    """
    if x1 < x < x2 and y1 > y > y2: return True
    return False

def in_circle(x, y, xc, yc, r):
    """
    代入要測試的點座標 (x, y)
    圓心座標 (xc, yc)、半徑 r
    判斷點是否在圓形內
    """
    if (x-xc)**2 + (y-yc)**2 < r**2: return True
    return False

""" 讀取形狀 """
figures = [[]]
for line in sys.stdin:
    if line.strip() == "*": break
    data = line.split()
    if data[0] == "r":
        figures.append([0] + list(map(float, data[1:])))
    elif data[0] == "c":
        figures.append([1] + list(map(float, data[1:])))

""" 判斷點是否在圖形內並組合答案 """
result = []
i = 0
n = len(figures)
for line in sys.stdin:
    if line.strip() == "9999.9 9999.9": break
    i += 1
    state = False
    x, y = map(float, line.split())
    for j in range(1, n):
        if figures[j][0] == 0:
            if in_rectangle(x, y, figures[j][1], figures[j][2], figures[j][3], figures[j][4]):
                result.append(f"Point {i:d} is contained in figure {j:d}\n")
                state = True
        elif figures[j][0] == 1:
            if in_circle(x, y, figures[j][1], figures[j][2], figures[j][3]):
                result.append(f"Point {i:d} is contained in figure {j:d}\n")
                state = True
    if not state:
        result.append(f"Point {i:d} is not contained in any figure\n")
sys.stdout.write("".join(result))