ในข้อนี้ เราต้องการขับรถผ่านบีคอนให้มากที่สุด โดยรถจะเลี้ยวขวาได้เท่านั้น และห้ามเลี้ยวเกิน
กำหนดให้เส้นตรง เป็นเส้นตรงที่ลากผ่านจุด และ เราจะสามารถแบ่งบีคอนออกเป็น 3 ประเภทได้แก่ บีคอนที่อยู่เหนือ , บีคอนที่อยู่บน และบีคอนที่อยู่ใต้ จะขอเรียกว่าประเภทที่ 1, 2 และ 3 ตามลำดับ สังเกตว่าสำหรับการขับรถขาไปจะเลี้ยวรถได้แค่ เท่านั้น จึงทำให้เราจะไม่สามารถขับรถเพื่อไปเก็บจากบีคอนประเภทที่ 2 และ 3 ได้ เมื่อผ่านบีคอนประเภทที่ 2 หรือ 3 แล้ว จะไม่สามารถไปถึงพิกัด ได้
ข้อสังเกตอีกอย่างคือ หากเราขับรถผ่านบีคอนประเภทที่ 2 เราจะไม่สามารถเลี้ยวได้อีกเพราะจะทำให้ไม่สามารถไปถึงพิกัด ได้ ดังนั้นจึงต้องขับรถตามเส้นตรง ตลอดจนกว่าจะถึงพิกัด จึงสรุปได้ว่าในการขับรถทั้งขาไปและขากลับ จะเลือกเก็บบีคอนได้เพียง 1 ประเภทเท่านั้น
จากข้อสังเกตเหล่านี้ เราจึงสรุปได้ว่าในการขับรถขาไป เราจะสามารถขับผ่านบีคอนได้แค่บีคอนประเภทที่ 1 และ 2 เท่านั้น และในทำนองเดียวกัน สำหรับการขับรถขากลับ ก็จะผ่านบีคอนประเภทที่ 2 และ 3 ได้เท่านั้นเช่นกัน
กำหนดให้ , และ แทนแต้มที่มากที่สุดที่ได้จากการขับรถผ่านบีคอนประเภทที่ 1, 2 และ 3 ตามลำดับ โดย จะพิจารณาการขับรถขาไปเท่านั้น และ จะพิจารณาการขับรถขากลับเท่านั้นเช่นกัน เราจะสามารถสรุปได้ทันทีว่า เท่ากับจำนวนบีคอนประเภทที่ 2 เพราะเราสามารถขับผ่านทุกบีคอนประภทที่ 2 ได้ ดังนั้นจึงเหลือ และ ที่จะต้องมาคำนวณ ซึ่งจะขออธิบายวิธีการคำนวณ เท่านั้น เนื่องจากวิธีการคำนวณ มีความคล้ายลึงกันมาก
กำหนดให้เซตของพิกัด เมื่อ คือพิกัดของบีคอนประเภทที่ 1 ลำดับที่ และ คือจำนวนบีคอนประเภทที่ 1 และ แทนสมาชิกของ ตัวที่ เราจะทำการหา ด้วยการใช้ Dynamic Programming ดังนี้ กำหนดให้ แทนแต้มที่มากที่สุดที่ได้จากการขับรถมาจนถึงพิกัด พิจารณาพิกัด และ ใด ๆ ถ้า และรถจะเลี้ยวขวาเมื่อขับจาก มา จะแก้ไขให้ แต่เนื่องจากหากเรานิยาม ตามนี้แล้ว เราจะไม่สามารถทราบได้ว่าการขับรถจาก มา เลี้ยวขวาหรือไม่
ดังนั้น เราจะพิจารณาพิกัด และ ตามความชันของเส้นตรงที่ลากผ่านสองจุดนี้ซึ่งแทนองศาของรถขณะขับผ่านทั้งสองจุด จากมากไปน้อย เพื่อรับประกันว่า การขับรถจาก มา จะเลี้ยวขวาเสมอ โดยเราจะสนใจ และ ที่ความชันของเส้นตรงที่ลากผ่านสองจุดนี้อยู่ในช่วง เนื่องจากรถสามารถเลี้ยวได้เพียง ดังที่ได้กล่าวไว้ในย่อหน้าที่ 2
ในตอนแรก เราจะกำหนดให้ และ สำหรับ เพื่อแสดงว่า ยังไม่ได้นับการคำนวณหากมีค่าเท่ากับ และเมื่อคำนวณค่า เป็นที่เรียบร้อยแล้ว เราจะได้ว่า เนื่องจากพิกัด เป็นสมาชิกลำดับที่ ของ และต้องลบ 2 ออกจาก เพราะได้นับแต้มรวมพิกัด และ ด้วย
หลังจากทราบค่า , และ เป็นที่เรียบร้อยแล้ว คำตอบของข้อนี้คือ ซึ่งมาจากการที่เราสามารถขับผ่านบีคอนประเภทที่ 2 ได้อย่างมาก 1 ครั้ง
โค้ดตัวอย่างดังนี้
#include <bits/stdc++.h> using namespace std; const int N = 2e3 + 5; double slope(pair<int, int> a, pair<int, int> b) { // Function for caculating slope given 2 points if (a.first == b.first) return 1e9; return (double)(a.second - b.second) / (double)(a.first - b.first); } int solve(vector<pair<int, int>> &V) { // Function for caculating ans_1 and // ans_3 int sz = V.size(); vector<pair<int, int>> line; for (int i = 0; i < sz; i++) for (int j = 0; j < i; j++) { if (slope(V[i], V[j]) < 0) continue; line.emplace_back(i, j); } sort(line.begin(), line.end(), [&](const pair<int, int> &a, const pair<int, int> &b) { // Sort by slope in descending order double m1 = slope(V[a.first], V[a.second]); double m2 = slope(V[b.first], V[b.second]); return m1 > m2; }); int dp[N]; memset(dp, -1, sizeof dp); dp[0] = 1; // Base case for (pair<int, int> l : line) // Dynamic Programming if (dp[l.second] != -1) dp[l.first] = max(dp[l.first], dp[l.second] + 1); return dp[sz - 1] - 2; } int A, n, diag; vector<pair<int, int>> hi, lo; int main() { scanf("%d %d", &A, &n); for (int i = 1, a, b; i <= n; i++) { scanf("%d %d", &a, &b); if (a == b) ++diag; else if (a < b) hi.emplace_back(a, b); else lo.emplace_back(A - a, A - b); } hi.emplace_back(0, 0), hi.emplace_back(A, A); lo.emplace_back(0, 0), lo.emplace_back(A, A); sort(hi.begin(), hi.end()), sort(lo.begin(), lo.end()); int high = solve(hi), low = solve(lo); printf("%d\n", max({high + low, high + diag, diag + low})); return 0; }
Time Complexity: