Moles

tocpc_moles

สังเกตว่าเราจะสามารถทุบตัวตุ่นตัวที่ jj ต่อจาก ii ก็ต่อเมื่อ sjsitjti|s_j-s_i|\leq t_j-t_i เมื่อ titjt_i\leq t_j

Subtask 1 ( si+1siti+1ti|s_{i+1}-s_i|\leq t_{i+1}-t_i และ titi+1t_i\leq t_{i+1} สำหรับ 1i<N1\leq i<N )

จากเงื่อนไขของ Subtask นี้ ทำให้สามารถทุบตัวตุ่นทุกตัวตามลำดับ 1,2,3,,N1,2,3,\dots,N ได้เสมอ ทำให้คำตอบคือค่า NN

Time Complexity: O(1)\mathcal{O}(1)

Subtask 2 ( si<si+1,ti<ti+1s_i< s_{i+1},t_i< t_{i+1} สำหรับ 1i<N1\leq i< N และ N5000N\leq 5000 )

จากเงื่อนไขของ Subtask สังเกตได้ว่าลำดับของตัวตุ่นที่โดนทุบจะเป็นลำดับย่อยของตัวตุ่นตัวที่ 1,2,3,,N1,2,3,\dots,N เนื่องจากตัวตุ่นตัวที่ i+1i+1 จะโผล่มาหลังตัวที่ ii ดังนั้นเราสามารถใช้ Dynamic Programming ในการแก้ Subtask นี้ได้

กำหนดให้ dp(i)dp(i) เป็นจำนวนตัวตุ่นโดนทุบมากที่สุดที่เป็นไปได้เมื่อพิจารณาจากตัวที่ 11 ถึงตัวที่ ii และทุบตัวที่ ii ด้วย

Base Case:

dp(i)=1sis0tidp(i)=1 \quad |s_i-s_0|\leq t_i (สามารถทุบตัวตุ่นตัวนี้เป็นตัวแรกได้)

dp(i)=0dp(i)=0 \quad หากไม่เป็นไปตามเงื่อนไขด้านบน

Recurrence Formula:

dp(i)=max1j<i{dp(j)}+1dp(i)=\max\limits_{1\leq j<i}\{dp(j)\}+1

เมื่อ dp(j)0dp(j)\neq 0 (รองรับกรณีที่ตัวตุ่นไม่สามารถโดนทุบได้เป็นตัวแรก) และ sjsitjtis_j-s_i\leq t_j-t_i ไม่จำเป็นต้องใช้ค่าสัมบูรณ์เนื่องจากเงื่อนไขของ Subtask

คำตอบข้อนี้เป็น max1iN{dp(i)}\max\limits_{1\leq i\leq N}\{dp(i)\}

Time Complexity: O(N2)\mathcal{O}(N^2)

Subtask 3 ( N5000N\leq 5000 )

สำหรับ Subtask นี้ ใช้วิธีแก้คล้ายกันกับ Subtask 2 โดยเพื่อทำให้วิธีการแก้ Subtask นี้ง่ายขึ้น เราจะสมมติตัวตุ่นตัวที่ 00 ตำแหน่ง s0s_0 ณ เวลา t=0t=0 แทนตำแหน่งเริ่มต้นของเรา จากนั้น เรียงตัวตุ่นตามเวลา tit_i จากน้อยไปมาก แล้วทำ Dynamic Programming ดังนี้

Base Case:

dp(0)=1dp(0)=1 (เริ่มที่ตัวตุ่นสมมติจากที่นิยามไว้ข้างต้น)

Recurrence Formula:

dp(i)=max1j<i{dp(j)}+1dp(i)=\max\limits_{1\leq j<i}\{dp(j)\}+1

เมื่อ dp(j)0dp(j)\neq 0 (รองรับกรณีที่ตัวตุ่นไม่สามารถโดนทุบได้เป็นตัวแรก) และ sjsitjti|s_j-s_i|\leq t_j-t_i ไม่จำเป็นต้องใช้ค่าสัมบูรณ์ของ tjtit_j-t_i เนื่องจากเราได้เรียง tit_i จากน้อยไปมากแล้ว แต่ยังคงต้องใช้ค่าสัมบูรณ์ของ sjsis_j-s_i เพราะ Subtask นี้ไม่ได้รับประกันว่า sj>sis_j>s_i

คำตอบข้อนี้เป็น max1iN{dp(i)}\max\limits_{1\leq i\leq N}\{dp(i)\}

Time Complexity: O(N2)\mathcal{O}(N^2)

Subtask 4 ( ไม่มีเงื่อนไขเพิ่มเติม )

พิจารณาเงื่อนไข sjsitjti|s_j-s_i|\leq t_j-t_i จะได้ว่า titjsjsitjtit_i-t_j\leq s_j-s_i\leq t_j-t_i หรือ titjsjsit_i-t_j\leq s_j-s_i และ sjsitjtis_j-s_i\leq t_j-t_i

เราสามารถเขียนอสมการ 2 อสมการดังกล่าวในรูปต่อไปนี้: ti+sitj+sjt_i+s_i\leq t_j+s_j และ tisitjsjt_i-s_i\leq t_j-s_j ตามลำดับ สังเกตว่าหากทั้งสองเงื่อนไขนี้เป็นจริง เราจะสามารถทุบตัวตุ่นตัวที่ jj หลังจาก ii ทันทีได้ นอกจากนี้ หาก tj<tit_j<t_i อสมการดังกล่าวจะเป็นเท็จเสมอ (เนื่องจาก sjsi0|s_j-s_i |\geq 0)

ดังนั้น เราจะเรียงตัวตุ่นตามค่า ti+sit_i+s_i จากน้อยไปมาก ทำให้สำหรับตัวตุ่นตัวที่ i,ji,j ใด ๆ ที่ i<j,ti+sitj+sji<j,t_i+s_i\leq t_j+s_j เสมอ จากนั้น เราจะหาลำดับย่อยของตัวตุ่นที่ยาวที่สุด ที่มีเงื่อนไขเป็น tisitjsjt_i-s_i\leq t_j-s_j สำหรับตัวตุ่นตัวที่ i<ji<j ในลำดับย่อยนี้ นอกจากนี้เราจะไม่สนใจตัวตุ่นที่ไม่สามารถโดนทุบเป็นตัวแรกได้เช่นเดิม

การหาลำดับย่อยดังกล่าว เป็นการหา Longest Non-decreasing Subsequence สามารถหาได้ภายในเวลา O(NlogN)\mathcal{O}(N\log N) ด้วยวิธี Greedy Algorithm

Time Complexity: O(NlogN)\mathcal{O}(N\log N)

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;
}