From d5e3a217087730a1da63ff82a94f8587c15e5812 Mon Sep 17 00:00:00 2001 From: "phluenam@gmail.com" Date: Wed, 1 Nov 2023 00:13:17 +0800 Subject: [PATCH] Add 1151 --- md/1151.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 md/1151.md diff --git a/md/1151.md b/md/1151.md new file mode 100644 index 0000000..245f1c1 --- /dev/null +++ b/md/1151.md @@ -0,0 +1,50 @@ +ข้อนี้กำหนดให้มีต้นไม้ $N$ ต้น โดยต้นที่ $i$ สูง $H_i$ และจะเลือกตัดต้นไหนทิ้งก็ได้ + +ต้นที่ $j$ จะเห็นได้หากทุกต้น $i$ ที่ $i < j$ ที่ไม่โดนตัดมี $H_i < H_j$ (ไม่โดนบัง) + +โจทย์นี้ถามว่าหากเลือกตัดดีที่สุดจะเห็นได้มากสุดกี่ต้น + +### แนวคิด + +ข้อนี้เป็นโจทย์ Longest Increasing Subsequence (LIS) โดยตรงเพราะสามารถตัดทุกต้นที่อยู่นอก LIS ให้เหลือ LIS ที่เป็นต้นไม้ที่จะมองเห็นทั้งหมด + +### Longest Increasing Subsequence + +Longest Increasing Subsequence (ปัญหาลำดับย่อยเพิ่มยาวที่สุด) เป็นปัญหาที่ถามว่าหากมี Array $H_1, H_2, \dots, H_N$ จะสามารถเลือก Subsequence (ลำดับย่อย) $H_{a_1}, H_{a_2}, \dots, H_{a_c}$ โดยที่ $a_1 < a_2< \dots < a_c $ และ $H_{a_1} < H_{a_2}< \dots < H_{a_c}$ ที่ยาวสุดได้เท่าไหร่ + +สำหรับวิธีการหา Longest Increasing Subsequence จะสามารถใช้ Dynamic Programming โดยจะทำเป็นขั้นๆ หนึ่งขั้นสำหรับทุกค่า $H_i$ โดยเก็บค่า $DP[c]$ ที่แทนว่าหากเลือก Subsequence ใน $H_1, H_2, \dots, H_i$ ที่มีความยาว $c$ จะสามารถจบได้ด้วยค่าสุดท้ายต่ำสุดเท่าไหร่ + +สังเกตว่า $DP[0], DP[1] , \dots, DP[N] $ ควรเป็นลำดับไม่ลด $(DP[0] \leq DP[1] \leq \dots \leq DP[N])$ เพราะหากมีลำดับยาว $c$ ที่จบด้วยค่า $DP[c]$ จะเลือกตัดตัวสุดท้ายจากลำดับที่ได้ค่า $DP[c]$ ออกจะทำให้เหลือลำดับยาว $c-1$ ที่จบด้วยค่า $DP[c-1] < DP[c]$ + +ในตอนเริ่มจะมี $DP[c] = \infty$ สำหรับ $c\geq 1$ และ $DP[0]=-\infty$ แทน Subsequence ว่างที่มีความยาว $0$ และจบด้วยค่าต่ำสุด $-\infty$ เพราะจะเอาค่าอะไรมาต่อก็ได้โดยที่ Subsequence ที่ได้ยังเป็นลำดับที่เพิ่มอยู่ + +สมมิตว่า $DP[0], DP[1] , \dots, DP[N] $ เป็นลำดับไม่ลด สำหรับแต่ละ $i$ จะต้องหา $DP[x]$ ที่มี $x$ มากสุดที่ $DP[x] H_i$ สำหรับ $a > x$ (ถ้าเอาไปต่อจะไม่เป็นลำดับย่อยเพิ่ม) ดังนั้นการพิจารณาเพียง $DP[x]$ เพื่อแก้ค่า $DP[x+1]$ นั้นถูกต้องแล้ว + +คุณสมบัติไม่ลดของ $DP[0], DP[1] , \dots, DP[N] $ ทำให้เราสามารถใช้ Binary Search ในการหาค่า $x$ ดังกล่าวที่เป็นค่าที่มากสุดที่ $DP[x] < H_i$ ซึ่งใช้เวลา $\mathcal{O}(\log N)$ ในแต่ละครั้ง ทั้งขั้นตอนวิธีจึงใช้เวลา $\mathcal{O}(N \log N)$ + +คำตอบจะเป็นค่า $x+1$ มากที่สุดที่ได้จากแต่ละขั้น + +ตัวอย่างโค้ดประกอบคำอธิบาย + +```cpp + for (int i = 1; i <= n; i++) + DP[i] = 1000000000; + + int ans = -1000000000; + for (int i = 1; i <= n; i++) { + int b = 0, e = n, x = 0; + while (b <= e) { + int mid = (b + e) / 2; + if (DP[mid] < H[i]) { + x = max(x, mid); + b = mid + 1; + } else + e = mid - 1; + } + + DP[x + 1] = min(DP[x + 1], H[i]); + ans = max(ans, x + 1); + } +``` \ No newline at end of file