python 正常應該是過不了這題的,我猜啦,我用上了 sys.stdin ,用了一些莫名其妙的方法處理 MLE,面對 #4 那個超大的測資檔依然 TLE
真的想用 python 寫的人可以去 o067 玩,基本邏輯是相同的
若你計算邏輯正確,把你用在這題的程式碼直接複製貼上過去那題應該就能 AC 了
--
希望有權限修這題測資的人能處理,至少測資格式要對啊!!
以下正文
--
先說結論,測資格式是絕對有問題的
#3, #4, #5 缺少換行符,有好幾行資料都放在同一行
在這三筆測資中,一行可不只 2 個數字,而是好幾個數字都放同一行!
可以理解為極端情況下有 10^7 +2 個數字塞在同一行,這不爆記憶體才怪!
下面我會說明我怎麼證明格式有問題
據題目所述
第一行有兩個數字 n , m 接下來有 m 行 每行有兩個數字 a b n < 10000 m < 10^7 1 <= a b <= n |
意味著我們可以相信無論如何,每一行最多就兩個數字,這兩個數字間用空格隔開
且這兩個數字的大小除了第一行的 m 有可能大到 10^7 這麼大外,
其他的 n, a, b 絕對不會超過 10000
意即,第一行最多 5 + 1 + 8 = 14 個字元 (最大就這樣 -> "1000 10000000")
其他每一行最多 5 + 5 = 10 個字元 (最大就這樣 -> "10000 10000",當然這是不合法輸入,a 不應與 b 相等,不過暫且把這算在內了)
如果就只有這樣,那 python 絕對可以應付,絕對不會 MemoryError
有超長字串的題目在 zerojudge 很多,但只要 python 能開起來,不至於讀一行資料就爆記憶體給你看
這題最多 14 個字元,沒道理一讀進來直接爆
所以要考慮的就是 IO 優化,改善讀取效率
於是我送出了我的第一版程式 (想抄就抄吧,反正不會 AC)
from sys import stdin |
結果是 NA (score:91%)
在 #4, #5, #6 這三個測資檔特別大的題目中都 MLE 了,應該也是大部分用 python 的人遇到的問題
就很怪異,對吧,我想過 TLE,但就是沒有想過 MLE
細讀了 RE 的資訊後,我發現出現 MLE 的位置還有不同
#4 和 #5 的 MLE 發生在讀取各節點相鄰資料的階段
#6 則是發生在第一行,才讀第一行就 MLE 了
就很離譜
如果就 2 個 5 位數字,第一行了不起多一個 8 位數,那也不可能這樣就爆記憶體了
思索解決方案後,我決定遇到 MLE 就瞎猜答案
於是我直接 try 捕捉 MemoryError,然後隨便亂填東西進去
from sys import stdin |
我用紅色標註起來的部分是我額外添加的,其他都與第一版相同
看上去穩了對吧? 絕對不會再吃 MLE 了,再吃我就倒立吃 ㄕ.....
實際上也確實如此
送出後得到的成績是 NA (score: 94%)
#6 那個在第一行就爆記憶體的測資檔 AC ,看來是我猜中答案了,#6 答案就是 "YES"
而 #4 和 #5 則吃了 ValueError,他們回傳的錯誤訊息都一樣
Traceback (most recent call last): File "/16380650_b924/code_16380650.py", line 16, in a, b = map(int, scan().strip().split()) ValueError: too many values to unpack (expected 2) |
對 python 夠熟悉的人應該皺眉了
a, b = map(int, scan().strip().split())
這一行程式碼在做的事情是這樣的
1. 讀取一行資料
2. 去掉頭尾多於空白字元
3. 根據空白字元的位置把字串轉換成 list
4. 把透過 map 把 list 的所有元素都轉換成 int,並返回一個迭代器
5. 解包,把裡面的元素依序賦值到 a 和 b 兩個變數
這是預設每一行字串只有 2 個數字才能用的寫法
如果 split() 後會超過 3 個或以上的元素,就會因為第三個以後的元素都沒有變數可以賦值,發生 ValueError: too many values to unpack
這段英文的意思用白話文描述,就是「太多元素需要解包了,只有 2 個不夠放」
啊題目不是在說明中保證每一行就兩個數字嗎,怎麼到這裡變一大堆都塞同一行?
這邊回傳的訊息足夠證明題目的測資格式是有問題的,不符合題意
c++ 能 AC 純粹是因為 scanf
不在乎空白字元是空格還是換行符 \n
,反正就是一率跳過,所以就算測資檔格式不正確依然能作答
但 python 沒有相同功能的函數,就只能一次讀一整行然後爆記憶體
至此已經確認測資檔就是有問題的,可以不用再試了,但我想再猜一把,娛樂一下
於是新的版本出現了
from sys import stdin |
我不再使用 bool 紀錄一個數字的總數是否為奇數,而是改用 set 紀錄總數為奇數的元素數量
如果讀到的數字不在 set 內,就加進去,反之則移除,這樣就可以保證 set 內一定只有總數奇數的元素
這樣改的目的是希望盡可能壓縮記憶體占用的空間,確保我只有保存奇數
try 的部分,除了 MemoryError 外,我多捕捉了一個 ValueError 應對有超過 3 個以上的數字放在同一行的問題
如果遇到就直接 continue 跳過
預期這段程式碼應該會吃 EOFError ,因為如果有幾行漏掉換行符,那 for 循環 m 次就會讀過頭。
但實際結果是在 #4 得到 TLE,然後就沒有然後了。
看來是 10^7 這麼多行還是太多了,沒辦法在時間內處理完。
這也是我開頭說 python 正常來說應該沒辦法 AC 這題的原因
因為忽視了 MLE,後面還有 TLE 在等著......
除非......你像我一樣,瞎猜答案,猜中了就有機會 AC......