#47529: 不用迴圈數學方法一行解(詳細講解!


ZhongWei (H₂SO₄)

學校 : 桃園市私立復旦高級中學
編號 : 213177
來源 : [61.216.138.167]
最後登入時間 :
2025-10-02 15:41:35

建議喜歡/想要一行解(少行數解)但很常不知道怎麼寫的python使用者參考看看

先給程式碼:

print(*[f'Case {i+1}: {(lambda a, b: (b-(b+1)%2 + a+(a+1)%2)*((b-(b+1)%2 - a-(a+1)%2)//2+1)//2 if b>a or b%2==a%2==1 else 0)(int(input()), int(input()))}' for i in range(int(input()))], sep='\n')

思路:將區間的開始與結束更新為奇數,用等差數列公式求解

從最裡面開始寫(基礎框架):

區間開始(大於a的最小奇數)a+(a+1)%2

區間結束(小於b的最大奇數)b-(b+1)%2

題目更新為[a+(a+1)%2, b-(b+1)%2]之間的所有奇數和

※注意到當a==b且兩數皆為偶數時,如a=4, b=4時,a與b的值會變為5及3,a>b,此例外要留意

帶入公式可得 得出所求=(a+(a+1)%2 + b-(b+1)%2) * (b-(b+1)%2 - a-(a+1)%2) / 2

 

輸入及輸出

由於a, b在公式中會使用到多於一次,所以我們不能用單純int(input())來取代a及b

所以我們就要使用非常強大的lambda匿名函式了

用法:lambda arguments expression

(基本上)相當於

def foo(arguements):
    return expression

用法(大致上)分為三種:

直接呼叫:如 print((lambda x: x**2+x+1)(int(input()))) #輸出int(input())代入f(x)=x^2+x+1的值

一行宣告函式:如 sqrt =  lambda x: round(r**0.5, 2) #程式碼即可呼叫sqrt(x)如一般函式一樣

內建函式(map(),sorted()等)的參數:例如以每一row的第二項排序二維陣列可使用sorted([[1, 2], [4, 1], [3, 1], [0, 3]], key=lambda l: l[1]) #[[3, 1], [4, 1], [1, 2], [0, 3]]

這題中我們可以這樣寫...

還記得前面說的例外嗎? 這個例外只會發生在a==b且a%2==b%2==0時,因為我們在寫的是expression而不是statement所以我們可以在同一行使用if..else...迴圈,其 syntax

expression if a else b

若是搭配loop comprehension: (題外話)

expression for i in list if a

expression if a else b for i in list

所以我們可以寫:

(lambda a, b: (前面推導出的公式) if b>a or b%2==a%2==1 else 0)(int(input()), int(input())) (後面的參數要代入兩個input)

於是我們就有single case的程式碼了

 

List comprehension, f-string, 以及 starred expression

如何寫成多組測資?

兩種寫法:A(將所有答案儲存在一個list中最後一起輸出) B(每計算完一組答案就輸出一次)

要一行解的話我們所有的for迴圈都要使用list comprehension,而其中不能寫statement只能寫expression,所以我們只能選擇A方案

list comprehension,簡單來說就是把

temp = []
for i in list:
    temp.append(i)

寫為

temp = [i for i in list]

於是我們的程式碼就成為了

print([(lambda a, b: (b-(b+1)%2 + a+(a+1)%2)*((b-(b+1)%2 - a-(a+1)%2)//2+1)//2 if b>a or b%2==a%2==1 else 0)(int(input()), int(input())) for i in range(int(input()))])

有一件事情很重要:我們可以這麼寫的原因是因為程式碼執行時會先讀到range()中的input()而不是lambda函式中的input(),如同一般for迴圈一樣

記得加[]或是在其他情況之下,加上你想要的資料型態,否則傳回的是一個generator object而不是list或其他資料型態

最後會輸出[9, 8]

但是我們想要的是Case #1....的輸出方式

所以我們就可以使用f-string了:)

這裡就不多介紹f-string了,篇幅真的太長了QQ

print([f'Case {i+1}: {(lambda a, b: (b-(b+1)%2 + a+(a+1)%2)*((b-(b+1)%2 - a-(a+1)%2)//2+1)//2 if b>a or b%2==a%2==1 else 0)(int(input()), int(input()))}' for i in range(int(input()))])

輸出['Case 1: 9', 'Case 2: 8']

最後我們有三種方式來完成此題

A) 使用starred expression搭配print()中的sep參數

print(*[f'Case {i+1}: {(lambda a, b: (b-(b+1)%2 + a+(a+1)%2)*((b-(b+1)%2 - a-(a+1)%2)//2+1)//2 if b>a or b%2==a%2==1 else 0)(int(input()), int(input()))}' for i in range(int(input()))], sep='\n')

B) 使用.join()方法

print('\n'.join([f'Case {i+1}: {(lambda a, b: (b-(b+1)%2 + a+(a+1)%2)*((b-(b+1)%2 - a-(a+1)%2)//2+1)//2 if b>a or b%2==a%2==1 else 0)(int(input()), int(input()))}' for i in range(int(input()))]))

C) 使用starred expression並修改f-string再搭配print()中的sep, end參數(千千萬萬拜託不要用這個

print(*[f'Case {i+1}: {(lambda a, b: (b-(b+1)%2 + a+(a+1)%2)*((b-(b+1)%2 - a-(a+1)%2)//2+1)//2 if b>a or b%2==a%2==1 else 0)(int(input()), int(input()))}\n' for i in range(int(input()))], sep='', end='')

 

這樣就可以AC了,希望有看到這裡的各位有學到一些東西:)

ps打這個報告花我超久...