codefroces中的病毒,這題有很深的trick,你能解開嗎?
大家好,歡迎閱讀週末codeforces專題。
我們今天選擇的問題是contest 1419的C題,目前有接近8000的人通過了本題。今天這題的難度不大,但是真的很考驗思維,一不小心就會踩中陷阱,我個人覺得非常有意思,適合週末動動腦。
題目連結:https://codeforces.com/contest/1419/problem/C
題意
有一個叫做Killjoy的特工發明了一種新型的冠狀病毒叫做Convid-2069,專門在codeforces平臺上傳播。這種病毒通過rating傳播,只要兩個人的rating一樣並且其中一個感染了病毒,那麼另外一個也會被感染。
這個病毒一開始的時候只有Killjoy自己感染了,他一共和n個人有聯絡。由於codeforces會定期舉辦比賽,參加比賽會改變一個人的rating,由於codeforces的規則,導致所有參賽的人的rating變動的總量為0,也就是說有人升了一定會有人降,大家的總和保持不變。已知Killjoy自己不會參賽,請問最少需要多少次比賽可以將所有人都感染。
對於每一次比賽,可以不必所有人都參與,傳染的發生不需要時間,瞬間就可以傳染。很容易證明,我們一定可以在有限次比賽當中將所有人都感染。
樣例
首先輸入一個t表示測試資料的組數( ),對於每一組資料第一行輸入兩個數,分別是n和x。n表示和Killjoy有接觸的人的數量,x表示Killjoy自己的rating,(
)。
第二行輸入n個整數,表示這n個人的rating。要求輸出一個整數,表示最少需要的比賽數量( )。
![](https://tva1.sinaimg.cn/large/007S8ZIlgy1gj3umjvi89j31da0ey3zh.jpg)
題解
這道題的思路非常直接,沒什麼彎彎繞,我們只需要觀察一下樣例就可以了。樣例當中有三組資料剛好對應了三種情況。
我們先來看第一種情況:這n個人的rating都和x相等,那麼意味著我們不需要比賽,就可以把所有人都感染了。結果當然是0,這一種非常簡單,大家應該都可以想明白。
第二種情況也不難,第二種情況就是雖然大家的rating不全等於x,但是大家的總和等於x * n。也就是說rating大於x的減小到x,小於x的增加到x,剛好可以通過一次比賽讓大家全部被感染,那麼最終的答案就是1。這對應樣例當中的68, 70的情況,x=69,很明顯68的增加1,70的減去1,就可以都變成69。
前面兩種理清楚了,再來看第三種情況,第三種情況也就是前面兩種都不符合的情況。也就是我們通過一次比賽沒辦法讓大家都等於x,不過這並沒有什麼關係,因為題目當中並沒有限制rating的範圍。我們完全可以讓其中n-1個人全部變成x,由於要保證大家的rating變動之和等於0,所以讓最後一個人來完成平衡的角色。
也就是說通過一次比賽,我們可以讓n-1個人全部被感染,最後留下一個人。那麼不難想出,我們只需要再多用一個回合就可以了。再多一個回合,我們可以讓第n個人變成x,讓一個已經感染的人來完成平衡。那麼,我們用了兩個回合就完成了所有人的感染。
整理一下思路,其實這題分為三種情況,第一種情況是大家全部都等於x,答案是0。第二種情況是大家可以只需要一個回合就變成x,如果上面兩種情況都不滿足的話,就額外再消耗一個回合即可。
這個思路也太簡單了,很快我就寫好了程式碼:
import math
t = int(input())
for _ in range(t):
n, x = list(map(int, input().split(' ')))
arr = list(map(int, input().split(' ')))
diff = 0
sdiff = 0
for i in range(n):
diff += abs(arr[i] - x)
sdiff += arr[i] - x
# 如果所有人都等於x,那麼會在一開始就被感染完
if diff == 0:
print(0)
# 如果可以通過一個回合讓所有人的rating調整到x,那麼只需要一個回合
elif sdiff == 0:
print(1)
else:
print(2)
但是很遺憾,當我提交了之後,並沒有AC,而是錯在了第二組資料。我想了很久,才終於想到了其中的trick。我先不說,大家先思考一下,看看能不能想到。
準備好了嗎?
我們剛才列舉的三種情況是沒有問題的,但是我們遺漏了一種。就是這一開始的n個人當中,可能有人的rating就等於x,所以他會在第一次比賽之前就感染。我們再想想最後一種情況,我們先把n-1個人的rating調整到x,再把調整當中付出的代價交給其中一個人來承擔。這也是我們需要第二個回合的原因,如果這n個人當中存在有人在開始之前就感染了,那麼我們完全可以讓這個已經感染的人來承擔代價,這樣我們就可以減少一個回合。
體現在程式碼當中,就是我們需要額外增加一個判斷條件,判斷一下這n個人當中是否存在有人的rating等於x,會在一開始的時候就被感染。如果有的話,答案就是1。
附上程式碼:
import math
t = int(input())
for _ in range(t):
n, x = list(map(int, input().split(' ')))
arr = list(map(int, input().split(' ')))
diff = 0
sdiff = 0
flag = False
for i in range(n):
if arr[i] == x:
flag = True
diff += abs(arr[i] - x)
sdiff += arr[i] - x
if diff == 0:
print(0)
# 如果存在人感染,也只需要一個回合就可以完成感染
elif sdiff == 0 or flag:
print(1)
else:
print(2)
這道題其實並不難,但是很容易漏掉這種情況,這也是codeforces當中題目的魅力所在,考驗我們思維的縝密與細緻程度。我個人覺得還是非常有趣的,值得一做。
今天的文章就到這裡,衷心祝願大家每天都有所收穫。如果還喜歡今天的內容的話,請來一個三連支援吧~(點贊、關注、轉發)
原文連結,求個關注
本文使用 mdnice 排版
- END -