熱門文章

2025年8月7日 星期四

ZeroJudge 解題筆記:b897. 10219 - Find the ways !

作者:王一哲
日期:2025年8月7日


ZeroJudge 題目連結:b897. 10219 - Find the ways !

解題想法


這題就是在計算組合數 $$ C^n_k = \frac{n!}{(n-k)! k!} = \frac{n(n-1)(n-2) \dots (n-k+1)}{k(k-1)(k-2) \dots \times 2 \times 1} $$ 取 $\log_{10}$ $$ \begin{align*} ans &= \log_{10} n + \log_{10} (n-1) + \log_{10} (n-2) + \dots + \log_{10} (n-k+1) \\ & ~~~~- (\log_{10} k + \log_{10} (k-1) + \log_{10} (k-2) + \dots + 0) \end{align*} $$ 最後再無條件進位到整數即為答案。
改用史特靈公式取近似,由其中一個表達式史特靈級數 $$ \ln n! = n \ln n - n + \frac{1}{2} \ln (2 \pi n) + \frac{1}{12n} - \frac{1}{360n^3} + \dots $$ 若忽略高次項並用換底公式換成以10為底的對數 $$ \begin{align*} \frac{\log_{10} n!}{\log_{10} e} &= n \cdot \frac{\log_{10} n}{\log_{10} e} - n + \frac{1}{2} \cdot \frac{\log_{10} (2 \pi n)}{\log_{10} e} \\ \log_{10} n! &= n \log_{10} n - n \log_{10} e + \frac{1}{2} \log_{10} (2 \pi) + \frac{1}{2} \log_{10} n \\ \log_{10} n! &\approx (n + 0.5) \log_{10} n - 0.4343 n + 0.39909 \end{align*} $$ 因此 $C^n_k$ 取 $\log_{10}$ $$ \begin{align*} & \\ \log_{10} C^n_k \approx & (n + 0.5) \log_{10} n - 0.4343 n + 0.39909 \\ & - [(n-k + 0.5) \log_{10} (n-k) - 0.4343 (n-k) + 0.39909] \\ & - [(k + 0.5) \log_{10} k - 0.4343 k + 0.39909] \end{align*} $$ 但是上式的第二行中有 $\log_{10}(n-k)$,當 $n=k$ 時會出問題,程式碼之中需要排除這個特例。

Python 程式碼


理論上用 math 函式庫中的 comb 可以很方便地計算組合數,但是這個函式在 Python 3.8 才加入,ZeroJudge 網站的 Python 版本為 3.6.9,不能用。
from math import comb, log10, ceil
import sys

for line in sys.stdin:
    n, k = map(int, line.split())
    print(ceil(log10(comb(n, k))))

改成不使用 comb,直接取 log10 ,還是會超時。
from math import log10, ceil
import sys

for line in sys.stdin:
    n, k = map(int, line.split())
    if n == k: print("1")
    else:
        ans = 0
        for i in range(n, n-k, -1): ans += log10(i)
        for i in range(k, 1, -1): ans -= log10(i)
        print(ceil(ans))

使用時間約為 17 ms,記憶體約為 3.3 MB,通過測試。
from math import log10, ceil
import sys

def fac(x):
    return (x+0.5)*log10(x) - 0.4343*x + 0.39909

for line in sys.stdin:
    n, k = map(int, line.split())
    if n == k: print("1")
    else: print(ceil(fac(n) - fac(n-k) - fac(k)))


2025年8月6日 星期三

ZeroJudge 解題筆記:b893. 勘根定理

作者:王一哲
日期:2025年8月6日


ZeroJudge 題目連結:b893. 勘根定理

解題想法


因為 $-2147483647 \leq x^6 \leq 2147483647 ~\Rightarrow -36 \leq x \leq 36$,只要一路由 $-36$ 每次加 1 檢測到 $36$ 即可。 這題的敘述有問題,題目中說無解時輸出 N0THING! >\\<,但實際上是 N0THING! >\\\<。

Python 程式碼


使用時間約為 19 ms,記憶體約為 3.3 MB,通過測試。
def func(x):
    return a*x**5 + b*x**4 + c*x**3 + d*x**2 + e*x + f

a, b, c, d, e, f = map(int, input().split())
if a == b == c == d == e == f == 0:
    print("Too many... = =\"")
else:
    real = False
    for i in range(-36, 36):
        if func(i) == 0:
            print(f"{i:d} {i:d}")
            real = True
        elif func(i)*func(i+1) < 0:
            print(f"{i:d} {i+1:d}")
            real = True
    if not real: print("N0THING! >\\\\\\<")


2025年8月5日 星期二

ZeroJudge 解題筆記:b877. 我是電視迷

作者:王一哲
日期:2025年8月5日


ZeroJudge 題目連結:b877. 我是電視迷

解題想法


這題可以用 if 判斷頻道號碼是否已經超過上限,從最前面繞回來;也可以取餘數找下一個頻道號碼。

Python 程式碼


使用時間約為 18 ms,記憶體約為 3.3 MB,通過測試。
a, b = map(int, input().split())
if b > a: print(b-a)
else: print(100-a+b)

將第2、3行合併。使用時間約為 17 ms,記憶體約為 3.3 MB,通過測試。
a, b = map(int, input().split())
print(b-a if b > a else 100-a+b)

取餘數,因為 Python 的取餘數若遇到被除數是負值,會先將被除數加上除數之後再取餘數,餘數和除數同號,不需要像 C++ 要在程式碼中自己加上除數量值。使用時間約為 18 ms,記憶體約為 3.3 MB,通過測試。
a, b = map(int, input().split())
print((b-a)%100)


2025年8月4日 星期一

ZeroJudge 解題筆記:b860. 獨角蟲進化計算器

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


ZeroJudge 題目連結:b860. 獨角蟲進化計算器

解題想法


用 while 迴圈不斷更新糖果、獨角蟲、鐵殼蛹的數量,直到獨角蟲的數量歸零為止。

Python 程式碼


使用時間約為 46 ms,記憶體約為 3.3 MB,通過測試。
c, w = map(int, input().split())  # 讀取糖果數量 c,獨角蟲數量 w
k = 0  # 鐵殼蛹數量 k

while w > 0:  # 如果 w 大於 0 繼續執行
    if c >= 12 and w >= 1:  # 如果 c 大於等於 12 而且 w 大於等於 1 才能進化
        c -= 10  # c 減 10,先用掉 12 顆,進化得 1 顆,再將鐵殼蛹送給博士得 1 顆
        w -= 1  # 進化,獨角蟲數量 w 減 1
        k += 1  # 鐵殼蛹數量 k 加 1
    else:  # 否則將獨角蟲送給博士換糖果
        w -= 1
        c += 1
# end of while loop
print(k)  # 印出答案


2025年8月3日 星期日

ZeroJudge 解題筆記:b836. kevin戀愛攻略系列題-2 說好的霸王花呢??

作者:王一哲
日期:2025年8月3日


ZeroJudge 題目連結:b836. kevin戀愛攻略系列題-2 說好的霸王花呢??

解題想法


共有 $n$ 片花瓣,第一次拔1片,接下來每次比上一次多拔 $m$ 片,假設共拔 $k$ 次,拔掉的花瓣總數為 $$ t = k + [m + 2m + 3m + \dots + (k-1)m] = k + \frac{(k-1)km}{2} = \frac{1}{2} [m k^2 + (2-m) k] $$ 若要剛好拔完,則 $t = n$,且 $k \in N$ 才能符合條件,因此 $$ mk^2 + (2-m)k - 2n = 0 $$ 若有正整數的根,輸出 "Go Kevin!!",否則輸出 "No Stop!!"。

Python 程式碼


使用時間約為 18 ms,記憶體約為 3.3 MB,通過測試。
import sys, math

for line in sys.stdin:  # 讀取多行測資直到 EOF 為止
    n, m = map(int, line.split())  # 花瓣數量 n,每次多拔的花瓣數量 m
    if m == 0:  # 如果 m 等於 0 一定有解
        print("Go Kevin!!")  # 印出 Go Kevin!!,繼續檢測下一行
        continue
    a, b, c = m, 2-m, -2*n  # 一元二次方程式的係數
    D = b*b - 4*a*c  # 判別式
    if D < 0:  # 判別式小於 0 無實數解
        print("No Stop!!")  # 印出 No Stop!!,繼續檢測下一行
        continue
    x1 = (-b + math.sqrt(D)) / (2*a)  # 較大的根
    x2 = (-b - math.sqrt(D)) / (2*a)  # 較小的根
    if x1 > 0 and int(x1) == math.ceil(x1):  # 如果 x1 是正整數
        print("Go Kevin!!")  # 印出 Go Kevin!!,繼續檢測下一行
        continue
    elif x2 > 0 and int(x2) == math.ceil(x2):  # 如果 x2 是正整數
        print("Go Kevin!!")  # 印出 Go Kevin!!,繼續檢測下一行
        continue
    else: print("No Stop!!")  # 否則印出 No Stop!!


2025年8月2日 星期六

ZeroJudge 解題筆記:b762. 英國聯蒙

作者:王一哲
日期:2025年8月2日


ZeroJudge 題目連結:b762. 英國聯蒙

解題想法


這題用字典或串列儲存對應的訊息,寫起來會比較簡潔。

Python 程式碼


使用時間約為 18 ms,記憶體約為 3.4 MB,通過測試。
act = {"Get_Kill": 1, "Get_Assist": 2, "Die": 3}  # 輸入的狀態
# 連續擊殺數對應的訊息
kill_mess = ["",
             "You have slain an enemie.",
             "You have slain an enemie.",
             "KILLING SPREE!",
             "RAMPAGE~",
             "UNSTOPPABLE!",
             "DOMINATING!",
             "GUALIKE!",
             "LEGENDARY!"]
# 陣亡時連續擊殺數對應的訊息
die_mess = [ "You have been slained.",
             "SHUTDOWN."]

N = int(input())  # 指令數量
cont = 0  # 連續擊殺數
kill = 0  # 總擊殺數
ast = 0  # 助攻次數
die = 0  # 陣亡次數
for _ in range(N):
    a = act[input().strip()]  # 讀取 N 行指令,要用 strip() 刪除某些測資後方多的 \t 或空白
    if a == 1:  # 如果是 Get_Kill
        cont += 1  # 連續擊殺數加 1
        if cont >= 8: print(kill_mess[8])  # 如果連續擊殺數大於等於 8,印出 kill_mess[8]
        else: print(kill_mess[cont])  # 否則印出 kill_mess[cont]
    elif a == 2: ast += 1  # 如果是 Get_Assist 助攻數加 1
    elif a == 3:  # 如果是 Die
        if cont < 3: print(die_mess[0])  # 如果連續擊殺數小於 3,印出 die_mess[0]
        else: print(die_mess[1])  # 否則印出 die_mess[1]
        die += 1  # 陣亡次數加 1
        kill += cont  # 更新擊殺總數
        cont = 0  # 連續擊殺數歸零
kill += cont  # 最後要再加上一次連續擊殺數
print(f"{kill:d}/{die:d}/{ast:d}")  # 印出答案


2025年8月1日 星期五

ZeroJudge 解題筆記:b759. 我明明就有說過= =

作者:王一哲
日期:2025年8月1日


ZeroJudge 題目連結:b759. 我明明就有說過= =

解題想法


這題可以只用字串切片或是索引值組合出每次要印出的內容,也可以每次都更新字串的內容,兩種方法的速度都很快。

Python 程式碼


使用時間約為 21 ms,記憶體約為 3.3 MB,通過測試。
X = input()
for i in range(len(X)):
    print(X[i:]+X[:i])

每次印出字串後,重新組合字串。使用時間約為 20 ms,記憶體約為 3.3 MB,通過測試。
X = input()
for i in range(len(X)):
    print(X)
    X = X[1:] + X[0]