สังเกตว่าเราจะสามารถทุบตัวตุ่นตัวที่ ต่อจาก ก็ต่อเมื่อ เมื่อ
Subtask 1 ( และ สำหรับ )
จากเงื่อนไขของ Subtask นี้ ทำให้สามารถทุบตัวตุ่นทุกตัวตามลำดับ ได้เสมอ ทำให้คำตอบคือค่า
Time Complexity:
Subtask 2 ( สำหรับ และ )
จากเงื่อนไขของ Subtask สังเกตได้ว่าลำดับของตัวตุ่นที่โดนทุบจะเป็นลำดับย่อยของตัวตุ่นตัวที่ เนื่องจากตัวตุ่นตัวที่ จะโผล่มาหลังตัวที่ ดังนั้นเราสามารถใช้ Dynamic Programming ในการแก้ Subtask นี้ได้
กำหนดให้ เป็นจำนวนตัวตุ่นโดนทุบมากที่สุดที่เป็นไปได้เมื่อพิจารณาจากตัวที่ ถึงตัวที่ และทุบตัวที่ ด้วย
Base Case:
(สามารถทุบตัวตุ่นตัวนี้เป็นตัวแรกได้)
หากไม่เป็นไปตามเงื่อนไขด้านบน
Recurrence Formula:
เมื่อ (รองรับกรณีที่ตัวตุ่นไม่สามารถโดนทุบได้เป็นตัวแรก) และ ไม่จำเป็นต้องใช้ค่าสัมบูรณ์เนื่องจากเงื่อนไขของ Subtask
คำตอบข้อนี้เป็น
Time Complexity:
Subtask 3 ( )
สำหรับ Subtask นี้ ใช้วิธีแก้คล้ายกันกับ Subtask 2 โดยเพื่อทำให้วิธีการแก้ Subtask นี้ง่ายขึ้น เราจะสมมติตัวตุ่นตัวที่ ตำแหน่ง ณ เวลา แทนตำแหน่งเริ่มต้นของเรา จากนั้น เรียงตัวตุ่นตามเวลา จากน้อยไปมาก แล้วทำ Dynamic Programming ดังนี้
Base Case:
(เริ่มที่ตัวตุ่นสมมติจากที่นิยามไว้ข้างต้น)
Recurrence Formula:
เมื่อ (รองรับกรณีที่ตัวตุ่นไม่สามารถโดนทุบได้เป็นตัวแรก) และ ไม่จำเป็นต้องใช้ค่าสัมบูรณ์ของ เนื่องจากเราได้เรียง จากน้อยไปมากแล้ว แต่ยังคงต้องใช้ค่าสัมบูรณ์ของ เพราะ Subtask นี้ไม่ได้รับประกันว่า
คำตอบข้อนี้เป็น
Time Complexity:
Subtask 4 ( ไม่มีเงื่อนไขเพิ่มเติม )
พิจารณาเงื่อนไข จะได้ว่า หรือ และ
เราสามารถเขียนอสมการ 2 อสมการดังกล่าวในรูปต่อไปนี้: และ ตามลำดับ สังเกตว่าหากทั้งสองเงื่อนไขนี้เป็นจริง เราจะสามารถทุบตัวตุ่นตัวที่ หลังจาก ทันทีได้ นอกจากนี้ หาก อสมการดังกล่าวจะเป็นเท็จเสมอ (เนื่องจาก )
ดังนั้น เราจะเรียงตัวตุ่นตามค่า จากน้อยไปมาก ทำให้สำหรับตัวตุ่นตัวที่ ใด ๆ ที่ เสมอ จากนั้น เราจะหาลำดับย่อยของตัวตุ่นที่ยาวที่สุด ที่มีเงื่อนไขเป็น สำหรับตัวตุ่นตัวที่ ในลำดับย่อยนี้ นอกจากนี้เราจะไม่สนใจตัวตุ่นที่ไม่สามารถโดนทุบเป็นตัวแรกได้เช่นเดิม
การหาลำดับย่อยดังกล่าว เป็นการหา Longest Non-decreasing Subsequence สามารถหาได้ภายในเวลา ด้วยวิธี Greedy Algorithm
Time Complexity:
Solution Code:
#include <bits/stdc++.h> #define pii pair<int, int> #define x first #define y second using namespace std; const int N = 1e6 + 5; int n, st; int dp[N]; pii A[N]; int main() { scanf("%d %d", &n, &st); for (int i = 1; i <= n; i++) { scanf("%d %d", &A[i].x, &A[i].y); int a = A[i].y - A[i].x; int b = A[i].y + A[i].x; A[i] = pii(a, b); } sort(A + 1, A + n + 1); vector<int> lis; for (int i = 1; i <= n; i++) { if (A[i].x < -st || A[i].y < st) continue; if (lis.empty() || lis.back() <= A[i].y) { lis.emplace_back(A[i].y); continue; } auto it = upper_bound(lis.begin(), lis.end(), A[i].y); if (it == lis.end()) continue; *it = A[i].y; } printf("%d\n", (int)lis.size()); return 0; }