programming.in.th · ข้อ 2041
ออกจากเมือง 1 แล้วกลับมาให้พอดีวันที่ T ซึ่งไกลถึงพันล้าน เริ่มจากไล่ทุกเส้นทางกับตารางรายวันที่ได้ 40% แล้วหั่นเมืองเป็นสำเนาจนทุกวันเป็นก้าวแบบเดียวกัน หนึ่งวันกลายเป็นการคูณเมทริกซ์แบบ max-plus ที่กระโดดข้ามช่วงระหว่างเทศกาลได้
อาณาจักรเอลฟ์มี N เมือง เมืองที่ i ทำอาหารที่ให้ความพึงพอใจ C[i] หน่วย
ถนนในอาณาจักรเป็นทางเดียวทั้งหมด M เส้น ถนนเส้นหนึ่งพาจากเมือง u ไปเมือง v
และใช้เวลา w วัน ออกจาก u วันที่ d ก็ไปถึง v วันที่ d + w
นักชิม W เริ่มที่เมือง 1 ในวันที่ 0 และต้องกลับมารายงานตัวที่เมือง 1 ในวันที่ T พอดี ห้ามหยุดพักระหว่างทาง
พอถึงเมืองไหนเขาชิมทันทีแล้วออกเดินทางต่อในวันนั้นเลย กลับมาเมืองเดิมกี่รอบก็ได้ความพึงพอใจเท่าเดิมทุกรอบ
นอกจากนี้ยังมีเทศกาลอาหาร k งาน งานที่ i จัดวันที่ t ที่เมือง x
ถ้าเขาอยู่ที่เมืองนั้นพอดีวันนั้นก็ได้เพิ่มอีก y หน่วย เราต้องบอกว่าความพึงพอใจรวมที่มากที่สุดเป็นเท่าไร
อินพุต / ขอบเขต / เอาต์พุต
N M T k บรรทัดที่สองคือ C[1..N]
ต่อด้วย M บรรทัด บรรทัดละ u v w แทนถนนทางเดียวจาก u ไป v
ใช้เวลา w วัน แล้วปิดด้วย k บรรทัด บรรทัดละ t x y แทนเทศกาล
1 ≤ N ≤ 50, N ≤ M ≤ 501,
1 ≤ T ≤ 1,000,000,000, 0 ≤ k ≤ 200,
1 ≤ C[i] ≤ 52,501, 1 ≤ w ≤ 5,
1 ≤ t ≤ T (แต่ละงานจัดคนละวัน) และ 1 ≤ y ≤ 1,000,000,000
เวลา 2 วินาที หน่วยความจำ 512 เมกะไบต์
T พอดีไม่ได้เลย ให้ตอบ -1 N ≤ 5, M ≤ 50 และ T ≤ 5
อีก 20% มี M ≤ 50 และ T ≤ 52,501
อีก 10% มี M ≤ 50 โดยที่ N = M, u[i] = i และ v[i] = (i mod N) + 1
อีก 15% มี M ≤ 50 และ k = 0
อีก 10% มี M ≤ 50 และ k ≤ 10
อีก 10% มี M ≤ 50 เฉย ๆ
และอีก 15% ไม่มีเงื่อนไขเพิ่มเติม
| Input | Output |
|---|---|
| 3 4 11 0 1 3 4 1 2 1 2 1 3 2 3 2 3 1 4 | 13 |
| 4 8 16 3 3 1 2 4 1 2 1 1 3 1 1 3 2 3 4 3 2 3 2 3 2 1 4 2 1 4 1 5 3 3 5 1 2 5 5 4 20 | 39 |
อ่านตัวอย่างนี้ยังไง
2 1 3 คือไปจากเมือง 2 ถึงเมือง 1 ใน 3 วัน เดินสวนทางไม่ได้
คำตอบมีหน่วยเป็นความพึงพอใจรวม ไม่ใช่จำนวนวันหรือจำนวนเมืองที่แวะ
และเป็น -1 เมื่อกลับถึงเมือง 1 ในวันที่ T พอดีไม่ได้
นับทั้งวันที่ 0 และวันที่ T เพราะเขาชิมตั้งแต่วันแรกที่ยืนอยู่เมือง 1 และชิมอีกครั้งตอนกลับถึง
แผนที่โจทย์ยกมาคือ 1 → 2 → 1 → 2 → 3 → 1 (บัญชีทางขวาของรูปข้างบน) รวม 1 + 3 + 1 + 3 + 4 + 1 = 13
ชุดที่สองมีเทศกาล 3 งาน อินพุตให้มาเป็นวันที่ 3, 1, 5 ซึ่งไม่ได้เรียงตามวัน แผนที่ชนะคือ 1 → 3 → 4 → 2 → 3 → 4 → 1 ไปตรงงานเดียวคือ วันที่ 5 ที่เมือง 4 ได้เพิ่ม 20 อีก 2 งานไม่คุ้มที่จะแวะ รวมได้ 39
ใบ้
ถ้า T เล็ก ข้อนี้คือตารางธรรมดา ช่องหนึ่งช่องคือ “วันที่ d ยืนอยู่เมือง v
แล้วได้มากที่สุดเท่าไร” ไล่จากวันที่ 0 ไปจนถึงวันที่ T แล้วอ่านคำตอบที่ช่องของเมือง 1
การจดคำตอบย่อยลงตารางแล้วหยิบมาใช้ซ้ำแบบนี้เรียกว่า DP (dynamic programming อ่านว่า “ไดนามิก โปรแกรมมิง”)
ปัญหาคือ T ใหญ่ได้ถึง 1,000,000,000 ตารางนั้นมีแถวเป็นพันล้านแถว
ลองดูขอบเขตอีกสองตัว เมืองไม่เกิน 50 เมือง และถนนยาวไม่เกิน 5 วัน ทั้งคู่เล็กมากเมื่อเทียบกับ T
ถ้าถนนทุกเส้นยาว 1 วัน ทุกวันจะใช้กฎเดียวกัน และอะไรที่ซ้ำเดิมทุกครั้งมักกระโดดข้ามทีละเยอะได้
แล้วถนนที่ยาวไม่เท่ากันล่ะ จะทำให้มันยาวเท่ากันได้ไหม
อาณาจักรเดียวกับตัวอย่างแรก ลองเดินให้กลับถึงเมือง 1 พอดีวันที่ 11 ก่อน แล้วค่อยไล่หายอดที่มากที่สุด
ชุดนี้ไม่มีเทศกาล
ชุดนี้ไม่มีเทศกาล
เทศกาล: วันที่ 5 ที่เมือง 4 ได้เพิ่ม 15
ชุดนี้ไม่มีเทศกาล
กดถนนที่อยากไป วงกลมสีทองคือเมือง 1 ซึ่งเป็นทั้งจุดเริ่มและจุดจบ
ได้ความพึงพอใจทุกครั้งที่เหยียบเมือง รวมวันที่ 0 และวันสุดท้ายด้วย แต่ทริปจะนับก็ต่อเมื่อวันสุดท้ายคุณยืนอยู่ที่เมือง 1 พอดี
ลองให้ครบทั้งสี่ชุดก่อนเปิดเฉลย ชุดสุดท้ายมีเรื่องให้สังเกต
ชุด “เมืองอร่อยที่สุด” ในเกมบอกไว้แล้วว่าเลือกถนนที่คุ้มที่สุดทีละก้าวไม่ได้ คนที่เด้งเก็บเมือง 3 จนเพลินจะกลับบ้านไม่ทันวันที่ 9 ต้องมองทั้งเส้นทางพร้อมกัน
ไล่จากช้าไปเร็วมีสามขั้น ตอนนี้เล่าสองขั้นแรก
วิธีที่ 1
ทุกวันที่เพิ่ม งานคูณด้วยจำนวนถนนที่ออกจากเมือง
ทุกเมืองลองถนนทุกเส้นที่ออกไป จนครบ T วัน แล้วเก็บเส้นที่จบที่เมือง 1
20% (T ไม่เกิน 5)
วิธีที่ 2
ดูถนนครบ M เส้นทุกวัน รวม T × M ครั้ง
จำค่าที่ดีที่สุดของทุกคู่ (วัน, เมือง) ไว้ เส้นทางที่มาถึงจุดเดียวกันไม่ต้องคิดต่อซ้ำ
40% (T ไม่เกิน 52,501)
วิธีเต็ม
ราว 7.3 × 108 ครั้งในเคสหนักสุดที่ผมสร้าง
ให้ทุกวันใช้กฎชุดเดียวกัน แล้วกระโดดข้ามวันทีละก้อน (ตอนที่ 3 ถึง 5)
100%
วิธีที่ 1 แย่ที่สุดในชุด T ไม่เกิน 5 คือถนน 50 เส้นวนอยู่ที่เมือง 1 ยาววันละเส้น ได้ 505 = 312,500,000 เส้นทาง ผมวัดได้ 1.2 วินาที ทันลิมิต 2 วินาที
วิธีที่ 2 คือ DP ที่ใบ้ไว้ มาจากข้อสังเกตเดียว สองเส้นทางที่มาถึงเมืองเดียวกันในวันเดียวกัน เดินต่อได้ทางเดียวกันทุกทาง เก็บไว้แค่เส้นที่ได้มากกว่าก็พอ
ช่องของตารางรายวัน
dp[d][v] คือความพึงพอใจรวมมากที่สุด ถ้าวันที่ d ยืนอยู่เมือง v โดยนับ C[v] ของวันนั้นแล้วdp[0][1] = C[1]u → v ยาว w วันทุกเส้นที่เข้าเมือง v: dp[d][v] = มากสุดของ dp[d − w][u] + C[v]v ก็บวก y เพิ่มเข้าช่องนั้นdp[T][1] และถ้าช่องนั้นไปไม่ถึงก็ตอบ -1| วันที่ | เมือง 1 | เมือง 2 | เมือง 3 |
|---|---|---|---|
| 0 | 1 | · | · |
| 1 | · | 4 | · |
| 2 | · | · | · |
| 3 | · | · | 8 |
| 4 | 5 | · | · |
| 5 | · | 8 | · |
| 6 | · | · | · |
| 7 | 9 | · | 12 |
| 8 | 9 | 12 | · |
| 9 | · | 12 | · |
| 10 | · | · | 16 |
| 11 | 13 | · | 16 |
ช่องคำตอบมาจากไหน
เมือง 1 มีถนนเข้า 2 เส้น คือ 2→1 (3 วัน) และ 3→1 (4 วัน)
ช่อง dp[11][1] เลยเลือกจาก dp[8][2] + 1 = 12 + 1 = 13 กับ dp[7][3] + 1 = 12 + 1 = 13
ได้ 13
สองทางได้เท่ากัน ตัวอย่างนี้มีสองเส้นทางที่ได้ 13 แผนที่โจทย์ยกมาคือเส้นที่ผ่านเมือง 3 ในวันที่ 7 โจทย์ต้องการแค่ตัวเลข เส้นไหนก็ตอบถูก
| คะแนน | เงื่อนไข | ไล่ทุกเส้นทาง | ตารางรายวัน |
|---|---|---|---|
| 20% | N ≤ 5, M ≤ 50, T ≤ 5 | ได้ | ได้ |
| 20% | M ≤ 50, T ≤ 52,501 | ไม่ทัน | ได้ |
| 10% | M ≤ 50, เมืองต่อกันเป็นวงเดียว | ไม่ทัน | ไม่ทัน |
| 15% | M ≤ 50, ไม่มีเทศกาล | ไม่ทัน | ไม่ทัน |
| 10% | M ≤ 50, เทศกาลไม่เกิน 10 งาน | ไม่ทัน | ไม่ทัน |
| 10% | M ≤ 50 | ไม่ทัน | ไม่ทัน |
| 15% | ไม่มีเงื่อนไขเพิ่ม | ไม่ทัน | ไม่ทัน |
ตารางรายวันได้ 40% แล้ว ก่อนหาท่าใหม่ ลองวัดก่อนว่ามันขาดไปเท่าไร งานของมันโตตาม T ตรง ๆ
คิดเป็นตัวเลข
109 ครั้งต่อวินาทีเป็นตัวเลขกะแบบระวังไว้ก่อน โค้ดเต็มของหน้านี้วัดได้ราว 1.1 ถึง 1.6 × 109 ครั้งต่อวินาที
หน่วยความจำแก้ได้ ตารางทั้งใบกิน 400,000 เมกะไบต์ก็จริง แต่ถนนยาวไม่เกิน 5 วัน เก็บแค่ 6 แถวล่าสุดก็พอ ส่วนเวลาลดตามไม่ได้
ย้อนคิดจากงบ 2,000,000,000 ครั้งหารด้วย 1,000,000,000 วัน เหลือ 2 ครั้งต่อวัน ห่างจากการดูถนนครบ 501 เส้นในแต่ละวันไปไกล ต้องข้ามวันไปเป็นก้อน โดยไม่แตะทีละวัน
เป้าหมายที่ตัวเลขบอก
เมือง 50 เมืองอยู่ใต้ 405 สบาย ที่ยังติดคือการรวมแบบนี้ต้องการให้ทุกวันใช้กฎชุดเดียวกัน แต่ถนนยาว 1 ถึง 5 วัน คนที่ออกจากเมืองวันนี้อาจยังไม่ถึงไหนในวันพรุ่งนี้
ที่มาของแนวคิดนี้
ผมรู้จักท่ายกกำลังเมทริกซ์อยู่ก่อนแล้ว ตัวเลขในตอนที่ 2 บอกว่าต้องใช้ท่าตระกูลนี้ ที่ต้องตัดสินใจจริงคือจะทำให้ทุกวันหน้าตาเหมือนกันได้ยังไง
ตัวเลขที่ทำให้กล้าหั่นเมืองเป็นสำเนาคือ w ไม่เกิน 5 กับ N ไม่เกิน 50
คูณกันได้ 250 แบบ อยู่ใต้เพดาน 405 ของตอนที่ 2 ถ้า w ยาวถึงหลักพัน ท่านี้ใช้ไม่ได้
สิ่งที่ต้องรู้เกี่ยวกับตัวเขาในวันหนึ่ง เพื่อจะคิดวันถัดไปต่อได้ เรียกว่าสถานะ (state) ในตารางรายวัน สถานะคือเมืองที่ยืนอยู่ แต่คนที่อยู่บนถนนยังไม่ได้ยืนที่เมืองไหน เราต้องเพิ่มสถานะให้เขาด้วย
นึกภาพ
ซื้อตั๋วรถไปเมือง v ตั๋วเขียนว่าอีกกี่วันถึง ทุกคืนตัวเลขบนตั๋วลดลงหนึ่ง พอเหลือ 0 เขาก็ยืนอยู่ที่ v
แล้วต้องซื้อตั๋วใบใหม่ในวันนั้นเพราะห้ามพัก
สองคนที่ถือตั๋วเหมือนกันทุกตัวอักษร จะมาจากถนนเส้นไหนก็ตาม เก็บไว้แค่คนที่สะสมได้มากกว่าก็พอ
สถานะใหม่ (v, j) อ่านว่า “เมือง v อีก j วันถึง”
W คือความยาวถนนที่ยาวที่สุดในอินพุต(v, 0) แปลว่าวันนี้ยืนอยู่เมือง v(v, j) ที่ j ตั้งแต่ 1 ถึง W − 1 แปลว่าอยู่บนถนน และอีก j วันจะถึงเมือง vW ตัว (j = 0 ถึง W − 1) รวมเป็นสถานะ S = N × W ตัว ซึ่งไม่เกิน 50 × 5 = 250เมื่อมองแบบนี้ การเดินทางทั้งอาณาจักรเหลือกฎสองข้อ และทั้งสองข้อใช้เวลาหนึ่งวันเท่ากัน
u → v ยาว w วัน: ก้าวจาก (u, 0) ไป (v, w − 1) และได้ C[v] ตอนนี้
ที่เป็น w − 1 เพราะก้าวนี้เองกินไปแล้วหนึ่งวัน ถนนยาว 1 วันจึงพาไปถึง (v, 0) ในพรุ่งนี้พอดี
(v, j) ไป (v, j − 1) ได้ 0 และไปทางอื่นไม่ได้// สร้างเมทริกซ์ของหนึ่งวัน จากถนนกับโซ่สำเนาเมือง
// id(v, j) = หมายเลขสถานะของสำเนาที่ j ของเมือง v
for (auto [u, v, w] : edges)
A[id(u, 0)][id(v, w - 1)] = max(A[id(u, 0)][id(v, w - 1)], C[v]); // ออกเดินทาง จ่ายรางวัลตรงนี้
for (int v = 0; v < n; v++)
for (int j = 1; j < W; j++)
A[id(v, j)][id(v, j - 1)] = 0; // อยู่ระหว่างทาง ผ่านไปหนึ่งวัน
รางวัล C[v] ถูกจ่ายตั้งแต่ออกเดินทาง ทั้งที่มื้อนั้นยังไม่ได้กิน ตอนที่ 6 อธิบายว่าทำไมไม่นับเกิน
รูปข้างล่างกางขาสุดท้ายของแผนในตัวอย่างแรกออกเป็นการก้าววันละครั้ง
ตัวอย่างแรกมีกี่สถานะ
ค่าที่ดีที่สุดของทุกสถานะในวันหนึ่ง เก็บเป็นแถวตัวเลขแถวเดียวได้ ช่องละสถานะ แถวแบบนี้เรียกว่าเวกเตอร์ (vector) งานของตอนนี้คือหาเวกเตอร์ของวันพรุ่งนี้จากเวกเตอร์ของวันนี้
กฎสองข้อของตอนที่ 3 เขียนลงตารางสี่เหลี่ยมได้ ช่องแถว p หลัก q บอกว่าวันนี้อยู่ p
แล้วพรุ่งนี้อยู่ q ได้กี่หน่วย ตารางตัวเลขแบบนี้เรียกว่าเมทริกซ์ (matrix) ตั้งชื่อว่า A
| จาก \ ไป | (1,0) | (1,1) | (1,2) | (1,3) | (2,0) | (3,0) | (3,1) |
|---|---|---|---|---|---|---|---|
| (1,0) | · | · | · | · | 3 | · | · |
| (1,1) | 0 | · | · | · | · | · | · |
| (1,2) | · | 0 | · | · | · | · | · |
| (1,3) | · | · | 0 | · | · | · | · |
| (2,0) | · | · | 1 | · | · | · | 4 |
| (3,0) | · | · | · | 1 | · | · | · |
| (3,1) | · | · | · | · | · | 0 | · |
C[v] ของเมืองปลายทาง
ตารางเต็ม 12 × 12 มีช่องที่ก้าวได้ 13 ช่อง (4 จากถนน และ 9 จากการเลื่อน)
ที่เห็นนี้คือ 8 ช่องในบรรดา 7 สถานะที่ไปถึงจากเมือง 1
อีก 5 สถานะไม่มีทางไปถึงจาก (1,0) เพราะสำเนา (v, j) ต้องเริ่มจากถนนที่เข้าเมือง v และยาวกว่า j วัน ถนนเข้าเมือง 2 ยาวสุด 1 วัน (2,1) (2,2) (2,3) เลยไม่มีใครเข้าถึง ถนนเข้าเมือง 3 ยาวสุด 2 วัน (3,2) (3,3) เลยไม่มีใครเข้าถึง
กฎของหนึ่งวัน
ใหม่[q] = มากสุดของ เก่า[p] + A[p][q] เมื่อไล่ p ทุกสถานะ (ข้ามช่องที่เป็น ·)
เครื่องเดินข้างล่างทำกฎนี้กับตัวอย่างแรกทีละวัน ในคำอธิบาย อ่าน ← ว่า “รับค่ามาจาก” ช่อง (1,2) วันที่ 9 เป็นช่องแรกที่มีให้เลือกสองทาง คือถนนจาก (2,0) (12 + 1) หรือเลื่อนจาก (1,3) (13 + 0) แล้วเลือกค่าที่มากกว่า
คอลัมน์สีเขียวคือสำเนา j = 0 ตรงกับตารางรายวันของตอนที่ 1 ทุกช่อง
ตัวอย่างแรก 7 สถานะ เดินทีละวัน
| วันที่ | (1,0) | (1,1) | (1,2) | (1,3) | (2,0) | (3,0) | (3,1) |
|---|---|---|---|---|---|---|---|
| 0 | 1 | · | · | · | · | · | · |
| 1 | · | · | · | · | 4 | · | · |
| 2 | · | · | 5 | · | · | · | 8 |
| 3 | · | 5 | · | · | · | 8 | · |
| 4 | 5 | · | · | 9 | · | · | · |
| 5 | · | · | 9 | · | 8 | · | · |
| 6 | · | 9 | 9 | · | · | · | 12 |
| 7 | 9 | 9 | · | · | · | 12 | · |
| 8 | 9 | · | · | 13 | 12 | · | · |
| 9 | · | · | 13 | · | 12 | · | 16 |
| 10 | · | 13 | 13 | · | · | 16 | 16 |
| 11 | 13 | 13 | · | 17 | · | 16 | · |
ทีนี้ถ้ารู้เมทริกซ์ของ 1 วัน จะได้เมทริกซ์ของ 2 วันไหม ลองทำมือหนึ่งช่องก่อน จาก (1,0) ไป (1,2) ในสองวัน จุดพักที่ก้าวได้ทั้งสองท่อนมีตัวเดียวคือ (2,0) (ไปเมือง 2 แล้วออกต่อไปเมือง 1)
ได้ 3 + 1 = 4 และเครื่องเดินวันที่ 2 ช่อง (1,2) ก็เป็น 1 + 4 = 5 ถ้ามีจุดพักหลายตัว ก็บวกสองท่อนของแต่ละตัว แล้วเลือกค่ามากสุด
คูณเมทริกซ์แบบมากสุดบวก
(A·B)[p][q] = มากสุดของ A[p][m] + B[m][q] เมื่อไล่จุดพัก m ทุกตัว
หน้าตาเหมือนการคูณเมทริกซ์ที่เรียนกันในคณิตศาสตร์ เปลี่ยนแค่ “บวก” เป็น “มากสุด” และ “คูณ” เป็น “บวก”
ระบบตัวเลขแบบนี้เรียกว่าพีชคณิตมากสุดบวก (max-plus algebra อ่านว่า “แม็กซ์-พลัส”) บางตำราเรียกพีชคณิตเขตร้อน (tropical) ที่มาของชื่อที่เล่ากันบ่อยคือนักวิจัยฝรั่งเศสตั้งให้เป็นเกียรติแก่ Imre Simon นักวิทยาการคอมพิวเตอร์ชาวบราซิลที่เกิดในฮังการี
// หนึ่งวันคือการคูณหนึ่งครั้ง แต่บวกกลายเป็นมากสุด และคูณกลายเป็นบวก
// C[i][j] = ค่ามากที่สุดของ A[i][k] + B[k][j] เมื่อไล่ k ทุกตัว
for (int i = 0; i < S; i++)
for (int k = 0; k < S; k++) {
if (A[i][k] <= HALF) continue; // ไปจากสถานะ i ถึง k ไม่ได้ ข้าม
for (int j = 0; j < S; j++)
C[i][j] = max(C[i][j], A[i][k] + B[k][j]);
} การคูณนี้จะใส่วงเล็บตรงไหนก็ได้ผลเท่ากัน เดิน a วัน ต่อ b วัน ต่อ c วัน คือการต่อสามท่อนเป็นทางเดียว จะต่อสองท่อนแรกก่อนหรือสองท่อนหลังก่อน ก็ได้ทางเดินชุดเดียวกันมาเลือก
ความจริงข้อนี้ทำให้ยกกำลังได้ เมทริกซ์ของ 4 วันคือเมทริกซ์ของ 2 วันคูณตัวเอง เช่นช่อง (1,0) ไป (1,0) ของ 4 วันได้ 4 ตรงกับเครื่องเดินวันที่ 4 ที่ช่อง (1,0) เป็น 1 + 4 = 5
เก็บเมทริกซ์ของ 1, 2, 4, 8, … วันไว้ทุกชั้น ตารางแบบนี้เรียกว่าตารางกระโดด (binary lifting) เป็นท่าเดียวกับที่ข้อห้องประชุมใช้กระโดดข้ามงาน
เดิน 11 วันด้วยการกระโดด
ทุกชั้นเป็นกำลังของ A ตัวเดียวกัน คูณสลับลำดับกันได้ จะเริ่มจากบิตต่ำหรือบิตสูงก็ได้เมทริกซ์ของ 11 วันเหมือนกัน
การคูณเวกเตอร์กับเมทริกซ์ใช้ S × S ครั้ง ถูกกว่าคูณเมทริกซ์สองใบ S เท่า โค้ดเลยคูณเมทริกซ์แค่ตอนสร้างชั้น ส่วนการเดินหน้าใช้เวกเตอร์ล้วน
ที่ขอบเขตใหญ่สุด S = 250 สร้างชั้นด้วยการยกกำลังสองซ้ำ 29 ครั้ง ครั้งละ 15,625,000 การบวกเทียบ ทั้ง 30 ชั้นกินหน่วยความจำ 15 เมกะไบต์ จากลิมิต 512
ถึงตรงนี้ถ้าไม่มีเทศกาล ทั้งข้อจบแล้ว คือกระโดดรวดเดียว T วันแล้วอ่านช่อง (1,0)
แต่รางวัลของเทศกาลผูกกับวันเดียว ถ้ากระโดดข้ามวันนั้นไปก็ไม่มีจังหวะใส่รางวัล
ตัวอย่างที่สองมี 4 เมือง ถนน 8 เส้น T = 16 และเทศกาลตามลำดับในอินพุตคือ วันที่ 3 เมือง 3 +5, วันที่ 1 เมือง 2 +5, วันที่ 5 เมือง 4 +20
เทศกาลมีไม่เกิน 200 งาน เส้นเวลาถูกหั่นเป็นช่วงได้ไม่เกิน 201 ช่วง ทำแบบนี้
y เข้าช่อง (x, 0) ซึ่งแปลว่ายืนอยู่เมือง x พอดีวันนั้นTช่อง (x,0) ของแต่ละงานก่อนและหลังบวก เมื่อเดินตัวอย่างที่สองแบบนี้
ทุกงานได้บวกเข้าช่องของตัวเอง แต่เส้นทางที่ชนะผ่านแค่งานวันที่ 5 ค่าในช่องอื่นแพ้ไปเองตอนเลือกค่ามากสุดในวันถัด ๆ ไป
ค้างไว้ตั้งแต่ตอนที่ 3 คือกฎข้อแรกบวก C[v] ตอนก้าวจาก (u, 0) ไป (v, w − 1)
ถ้าวันที่ T มาถึงก่อนเขาไปถึงเมือง v ก็เท่ากับแจกรางวัลของมื้อที่ยังไม่ได้กิน
ข้อที่ค้ำทั้งหมด
ทางเดินใดก็ตามที่จบที่ (1,0) ในวันที่ T ประกอบด้วยถนนครบเส้นต่อกัน
เพราะเมื่อก้าวเข้า (v, w − 1) แล้ว ทางออกเดียวคือเลื่อนลงทีละหนึ่งจนถึง (v, 0)
รางวัลทุกก้อนที่จ่ายล่วงหน้าในวัน d เลยได้ลงจอดในวัน d + w ซึ่งไม่เกิน T
ดูของจริงจากเครื่องเดินในวันที่ 11
C[1] ที่จ่ายล่วงหน้าไว้แล้วตัวไล่ทุกเส้นทางที่ใช้เทียบเป็นอีกชั้นของความมั่นใจ มันบวกความพึงพอใจตอนไปถึงจริง และไม่รู้จักสำเนาเมือง ถ้าการจ่ายล่วงหน้านับเกิน ตัวเลขสองฝั่งจะแยกกันในเทสเล็ก ๆ ทันที
| ส่วนในโค้ด | อธิบายอยู่ที่ |
|---|---|
| struct MaxPlus (mul, vmul) | ตอนที่ 4 · กฎของหนึ่งวัน และการคูณแบบมากสุดบวก |
| // A = one-day transition matrix | ตอนที่ 3 · กฎสองข้อของสำเนาเมือง |
| // Binary powers of A ... และ advance() | ตอนที่ 4 · ตารางกระโดด |
| sort F แล้ว // Apply every festival held on day t | ตอนที่ 5 · เทศกาลหั่นเส้นเวลา |
| ans = vec[id(0, 0)] และคืน -1 | ตอนที่ 6 · อ่านคำตอบที่ (1,0) เท่านั้น |
| NEG กับ HALF | ย่อหน้าใต้โค้ด |
ตรวจอะไรไปแล้วบ้าง
ทั้งสามโปรแกรมตอบตัวอย่างได้ 13 กับ 39 และตรงกันใน 3,000 เคสสุ่มจิ๋ว (เมืองไม่เกิน 4, T ไม่เกิน 9) กับอีก 1,500 เคสจิ๋วที่ปล่อยให้เทศกาลซ้ำวัน โค้ดเต็มตรงกับตารางรายวันใน 3,000 เคสขนาดกลาง (T ไม่เกิน 3,000)
T ใหญ่ตรวจบนอาณาจักรที่เมืองต่อกันเป็นวงเดียว ซึ่งนับคำตอบได้ด้วยสูตรตรง 3,000 เคส T สุ่มถึง 1,000,000,000 มี 1,382 เคสที่ T ตั้งแต่ 229 ขึ้นไป คือใช้ชั้นกระโดดครบทั้ง 30 ชั้น และ 1,315 เคสเก็บเทศกาลได้จริง
ขอบเขตของการตรวจนี้คือกราฟหลายรูปแบบที่ T เล็ก กับ T ใหญ่บนวงเดียว ส่วนที่ครอบทุกขนาดคือเหตุผลในตอนที่ 3 ถึง 6
| โปรแกรม · เคส | วินาที | เมกะไบต์ |
|---|---|---|
| เต็ม · N = 50, M = 501, T = 1,000,000,000, เทศกาล 200 งานห่างกัน 222 − 1 วัน | 0.45 ถึง 0.64 | 18.1 |
| เต็ม · ขนาดเดียวกัน ไม่มีเทศกาล | 0.21 ถึง 0.27 | 18.1 |
| ตารางรายวัน · N = 20, M = 50, T = 52,501 | 0.01 | 14.3 |
| ไล่ทุกเส้นทาง · ถนน 50 เส้นวนที่เมือง 1, T = 5 | 1.2 | 3.2 |
ท่าที่ยกไปใช้ข้ออื่นได้คือ ถ้าอยากกระโดดข้ามเวลาเป็นก้อน ให้เพิ่มสถานะจนทุกหน่วยเวลาใช้กฎชุดเดียวกัน
(ข้อยุบสถานะให้เหลือแถวเดียวทิ้งท้ายไว้ว่าถ้า n ใหญ่กว่านั้นต้องยกกำลังเมทริกซ์ ข้อนี้คือท่านั้น)
ในหน้านี้