• 16 min

โจทย์จาก TOI14 ข้อ NBK48 ใน programming.in.th

เป็นข้อแรกๆเลยมั้งที่รู้สึกว่ามันง่ายกว่า TOI ข้ออื่นๆ เพราะใช้ Concept ที่ง่ายมาก ง่ายกว่า สอวน. ค่าย 2 บางข้ออีก แต่ก็ซ่อนไว้ดีมากเหมือนกัน

เป็ดไอคอนของเรื่องเล่าชาวอัลกอ Practical Algorithms
Practical Algorithms: เรื่องเล่าชาวอัลกอ
เพจที่อยากให้คนไทยมีเนื้อหาอัลกอริทึมดีๆ ให้ได้อ่านกัน
เป็ดชาวอัลกอกำลังนั่งดูรายการทีวี พูดว่า "ดูกี่ตอนดีนะ"

โจทย์

ความยาก ★★★☆☆

มีสารคดีทั้งหมด NN ตอน แต่ละเรื่องมีค่ารับชม pip_i บาท ในการรับชมสารคดี เราจะต้องดูต่อเนื่องกันตั้งแต่ตอนที่ 11 ถึงตอนที่ aaโดยที่สามารถเลือกค่า aa เองได้ โดยจะต้องเสียค่ารับชม p1,p2,p3,...,pap_1,p_2,p_3,...,p_a บาท

โดยโจทย์จะมีคำถามทั้งหมด QQ คำถาม ในแต่ละครั้งจะถามว่าถ้ามีเงิน qjq_j บาทจะสามารถชมสารคดีได้ทั้งหมดมากที่สุดกี่ตอน

โจทย์เต็มข้อ NBK48

ข้อมูลนำเข้า

บรรทัดแรก : บรรทัดแรก ระบุจำนวนเต็ม N,QN,Q (1N,Q1000001\leq N,Q \leq 100000) แทนจำนวนสารคดี และคำถาม

บรรทัดต่อมา ระบุจำนวนเต็ม pip_i ทั้งหมด NN ตัว แทนค่ารับชมของตอนที่ ii (10,000pi10,000-10,000\leq p_i\leq 10,000)

Q บรรทัดต่อมา ระบุจำนวนเต็ม qjq_j แทนจำนวนเงินของการถามครั้งที่ jj (0qj1,000,000,0000\leq q_j\leq 1,000,000,000)

ข้อมูลส่งออก

มี Q บรรทัดแต่ละบรรทัดแสดงจำนวนตอนมากที่สุดที่ดูได้ของแต่ละคำถาม

ตัวอย่าง

Input Output
5 1
10 20 -10 30 60
25
3

มีสารคดีทั้งหมด 5 ตอน

  • ตอนที่ 1 เสีย 10
  • ตอนที่ 2 เสีย 20
  • ตอนที่ 3 เสีย -10
  • ตอนที่ 4 เสีย 30
  • ตอนที่ 5 เสีย 60

ถ้ามีเงินทั้งหมด 25 บาทจะดูได้ถึงตอนที่ 3 เพราะจะใช้เงินเพียง 10 + 20 - 10 = 20 บาท


คำใบ้

ลองคิดกรณีที่ทุกตอนมีค่าไม่ติดลบก่อนแล้วค่อยๆ เริ่มคิดกรณีมีค่าติดลบ

วิเคราะห์โจทย์

ตอนแรกเราจะมาคิดกันก่อนว่าการที่จะดู aa ตอนแรก จะคำนวณค่ากันยังไง

เรารู้อยู่แล้วว่าถ้าดูแค่ตอนแรก ก็จ่ายแค่ตอนแรก ดังนั้นถ้าเรามี array ที่ใช้เก็บค่าใช้จ่ายในการดู ตั้งแต่ตอนแรกถึงแต่ละตอน (เรียกว่า cost ละกัน)

cost[1] ก็จะเท่ากับ p1p_1 เลย

ทีนี้จะคำนวณค่าดูถึงตอนที่ 2 จะต้องใช้ค่าดูตอนแรกรวมกับค่าดูตอนที่ 2 ซึ่ง สามารถเขียนได้ว่า

cost[2]=cost[1]+p2cost[2] = cost[1] + p_2

และถ้าสังเกตตอนถัดๆไป ค่าดูจากตอนแรกไปถึงตอนที่ i ก็จะเขียนได้ว่า

cost[i]=cost[i1]+picost[i] = cost[i-1] + p_i

สมมติตารางค่าดูแต่ละตอนเป็นดังนี้

1
2
3
1
2
4
1
5

array cost ค่าดูแต่ละตอนแยกกัน

ดังนั้นจากค่าดูแต่ละตอน เราก็สามารถแปลงเป็นค่าดูตั้งแต่ตอนแรกถึงตอนที่ ii ได้

1
3
6
7
9
13
14
19

array cost เมื่อคำนวณค่าดูตั้งแต่ตอนแรกแล้ว

ทีนี้เราก็จะรู้ว่าดูถึงเรื่องไหนแล้วต้องใช้เงินเท่าไหร่ แล้วถ้าไม่มีเรื่องไหนเลยที่มีค่าติดลบ เราก็จะสามารถใช้ binary search ในการค่าตอนที่มากที่สุดได้เลย

อย่างเช่นว่าถ้าเรามีเงิน 11 บาท ก็จะได้ว่า:

  1. ตอนที่ 4 ใช้เงิน 7 บาท ลองไปเช็กตอนถัดไปได้
1
3
6
7
9
13
14
19

ถ้าดูถึงตอนที่ 4 จะใช้เงิน 7 บาท ซึ่งเรามีเงินพอดูถึงตอนนี้ได้ (11)

  1. ตอนที่ 6 ใช้เงิน 13 บาท มีเงินไม่พอแล้ว ต้องดูถึงแค่ตอนก่อนหน้า
1
3
6
7
9
13
14
19

ถ้าไปดูถึงตอนที่ 6 เลย จะต้องใช้เงิน 13 ซึ่งมีไม่พอ ดังนั้นก็ไม่สามารถดูตอนหลังจาก 6 ได้เหมือนกัน

  1. ตอนที่ 5 ใช้เงิน 9 บาท มีเงินพอ และเพราะตอนที่ 6 ดูไม่ได้ ก็ตอบ 5
1
3
6
7
9
13
14
19

เราก็จะเหลือว่าต้องตรวจสอบว่าดูถึงตอนที่ 5 ได้ไหม

แล้วถ้าค่ารับชมเป็นลบล่ะ?

เราจะไม่สามารถใช้วิธี binary search ในการหาคำตอบได้แล้ว เพราะว่า array cost มันไม่ได้เรียงกันเหมือนเดิม

บางทีดูถึงตอนที่ 2 ต้องจ่าย 6 บาท แต่ถ้าดูถึงตอนที่ 5 อาจจะไม่ต้องจ่ายเลยก็ได้

1
5
-4
4
-6
-1
3
4

array cost ค่าดูแต่ละตอนแยกกัน แต่ติดลบ

1
6
2
6
0
-1
2
6

array cost อันใหม่ คำนวณค่าดูตั้งแต่ตอนแรกโดยที่มีตอนติดลบ

คำถามที่น่าคิดคือ…

ถ้าดูถึงตอนที่ i มันต้องจ่ายแพงกว่าดูเพิ่มไปอีกตอน แล้วเราสมควรดูเพิ่มไหม?

ซึ่งคำตอบสำหรับข้อนี้คือควรดู เพราะว่าจ่ายน้อยลง และมันก็ไม่ได้มีข้อเสียอย่างอื่นเพิ่มมา

1
6
2
6
0
-1
2
6

ถ้าดูถึงตอนที่ 5 จะจ่ายน้อยกว่าถึงแค่ตอนที่ 4

อย่างในตัวอย่างล่าสุด ถ้าการดูถึงตอนที่ 5 จะต้องจ่าย 0 บาท แต่ถ้าดูไม่ถึงจะต้องจ่ายมากกว่า 0 บาท ทำไมถึงจะหยุดก่อนตอนที่ 5 ล่ะ?

แปลว่าถ้าเรารู้ว่ายังมีตอนถัดไปที่ทำให้ราคาถูกกว่า แทนที่จะดูถึงแค่ตอนที่ xx เราก็ดูเพิ่มดีกว่า หมายความว่า
ตัวเลือกที่จะดูถึงตอนที่ xx เนี่ย ไม่ต้องคิดเลยก็ได้ เพราะยังไงก็ไม่ใช่คำตอบอยู่แล้ว

แล้วถ้าเราตัดทุกช้อยที่ไม่จำเป็นออกไป เราก็จะเหลือแค่

1
6
2
6
0
-1
2
6

array cost ค่าหลังตัดตัวเลือกที่ไม่จำเป็นออกไป

ที่มันก็กลายเป็น array ที่เรียงกันเหมือนเดิมแล้ว และเราก็ทำ binary search ได้เหมือนเดิม

ลิงก์เพิ่มเติม

โจทย์เต็มข้อ NBK48 โพสต์ Original ใน Facebook
0

บทความอื่นๆ