Bắt cóc

Xem PDF

Điểm: 400 (p) Thời gian: 1.0s Bộ nhớ: 256M Input: bàn phím Output: màn hình

\(dungde99\) đang có \(n\) buổi hẹn với \(n\) anh trai đỏ Codeforces vào ngày \(a_1, a_2, a_3,\cdots, a_n\) tương ứng (các ngày có thể trùng nhau). Tiếc là \(dungde99\) chỉ được nghỉ vào \(m\) ngày liên tiếp nên cô ấy muốn tranh thủ gặp càng nhiều anh trai đỏ Codeforces càng tốt.

Thế nhưng cuom1999 lại lên kế hoạch bắt đi mất một anh trai của \(dungde99\). Cụ thể là, cuom1999 sẽ tính toán chọn một người anh trai từ danh sách của \(dungde99\) sao cho số anh trai nhiều nhất \(dungde99\) có thể gặp được sau đi bị bắt mất một anh là ít nhất.

Hãy đưa ra số anh trai nhiều nhất \(dungde99\) có thể gặp được theo tính toán của cuom1999. Biết rằng cuom1999 cũng nick đỏ Codeforces nên luôn tìm cách chọn một anh trai tối ưu nhất.

Input

  • Dòng đầu chứa hai số nguyên \(n\), \(m\). Trong đó \(n\) là số buổi hẹn với các anh trai của \(dungde99\), \(m\) là số ngày nghỉ liên tiếp của \(dungde99\).
  • Dòng 2 chứa \(n\) số nguyên \(a_i\) là ngày gặp mặt anh trai thứ \(i\). (các số \(a_i\) được sắp xếp theo thứ tự tăng dần).

Ouput

  • Một dòng duy nhất đưa ra kết quả của bài toán.

Constraints

  • \(1 \leq a_i \leq 10^9\)
  • \(1 \leq m \leq 10^9\)

Scoring

  • Subtask \(1\) (\(10\%\) số điểm): \(1 \leq n \leq 100\)
  • Subtask \(2\) (\(40\%\) số điểm): \(1 \leq n \leq 10^4\)
  • Subtask \(3\) (\(50\%\) số điểm): \(1 \leq n \leq 10^6\)

Example

Test 1

Input
7 5    
1 3 7 10 11 19 20 
Output
2
Note

Ban đầu \(dungde99\) có thể gặp được nhiều nhất \(3\) anh trai ở vị trí \(3,4,5\). Nếu cuom1999 bắt đi một anh trai ở vị trí số \(3\) hoặc \(4\) hoặc \(5\) thì số anh trai gặp được nhiều nhất có thể của \(dungde99\)\(2\).


Bình luận


  • 11
    SPyofgame    3:00 p.m. 8 Tháng 6, 2020 chỉnh sửa 24

    Spoiler Alert


    Hint 1

    Xét một bài toán con: Cho mảng a[] gồm n phần tử. Tìm đoạn con a[l]..a[r] thỏa a[l] + k ≥ a[r]


    Hint 2

    Xài two-pointer, ta dễ dàng giải quyết vấn đề trên với độ phức tạp nhỏ hơn


    Reference bài toán con | \(O(n)\) time | \(O(1)\) auxiliary space | Two-pointers

    C++
    int n = readInt();
    vector<int> a(n);
    for (int &x : a) cin >> x;
    
    int max_size = 0;
    for (int l = 0, r = 0; l < n; ++l) /// O(n)
    {
        while (r + 1 < n && a[l] + k > a[r + 1]) r++; /// Two-pointer
        int cur_size = r - l + 1;
        max_size = max(max_size , cur_size);
    }
    cout << max_size ;
    

    Hint 3

    Xét bài toán đề yêu cầu. Với các bài toán con có n - 1 phần tử, ta tính toán.

    Kết quả sẽ là result = min{ giá trị các bài toán con }

    Ngoài việc thử tạo từng mảng con mà bị loại đi phần tử p. Ta có thể duyệt p qua và thực hiện swap(a[0], a[p + 1]) thì a[1]..a[n - 1] là một mảng con mới đã loại phần tử p + 1. Từ đó giảm độ phức tạp không gian


    Reference thuật trâu | 50 điểm + TLE | \(O(n ^ 2)\) time | \(O(1)\) auxiliary space | Brute-forces, Two-pointers

    C++
    int n = readInt();
    vector<int> a(n);
    for (int &x : a) cin >> x;
    
    int result = n;
    for (int p = 0; p + 1 < n; swap(a[0], a[p + 1]), ++p) /// O(n ^ 2)
    {
        int max_size = 0;
        for (int l = 0, r = 0; l < n; ++l) /// O(n)
        {
            while (r + 1 < n && a[l] + k > a[r + 1]) r++; /// Two-pointer
            int cur_size = r - l + 1;
            max_size = max(max_size, cur_size);
            if (max_size > result) break; /// Can
        }
        result = min(result, max_size);
    }
    cout << result;
    

    Hint 4

    Để bỏ vòng lặp ngoài, ta có nhận xét như sau: Ta chỉ cần tìm 2 đoạn con dài nhất ai..aj thỏa ai + k ≥ aj

    Gọi độ dài đoạn dài nhất là max_size1, độ dài đoạn dài nhì là max_size2, ta có:

    Xét 2 trường hợp

    • max_size1 ≠ max_size2 thì result = max_size1 - 1

      (loại bỏ đi một phần tử)

    • max_size1 = max_size2 thì result = max_size1

      (loại bỏ đi một phần tử của đoạn dài max_size1, nhưng vẫn còn đoạn dài max_size2 = max_size1)


    Reference Thuật tham lam | 81 điểm + WA | \(O(n)\) time | \(O(1)\) auxiliary space | Greedy, Two-pointers

    C++
    int n = readInt();
    vector<int> a(n);
    for (int &x : a) cin >> x;
    
    int max_size1 = 0, max_size2 = 0;
    for (int l = 0, r = 0; l < n; ++l) /// O(n)
    {
        while (r + 1 < n && a[l] + k > a[r + 1]) r++; /// Two-pointer
        int cur_size = r - l + 1;
    
             if (cur_size > max_size1) max_size2 = max_size1, max_size1 = cur_size;
        else if (cur_size > max_size2) max_size2 = cur_size;
    }
    cout << max_size1 - (max_size2 != max_size1);
    

    Hint 5

    Spot lỗi sai trong thuật trên nào: Đó là chưa xét trường hợp khi 2 đoạn con lồng vào nhau, dẫn tới việc khi xóa một phần tử chung của 2 đoạn con max_size1, max_size2 thì độ dài 2 đoạn con còn lại max_size1 - 1, max_size2 - 1 => res = max_size1 - 1

    Để sửa vấn đề này. Ta thêm 2 biến là:

    • pos_1 lưu vị trí cuối cùng của đoạn con đầu tiên dài max_size1

    • pos_2 lưu vị trí đầu tiên của đoạn con cuối cùng dài max_size2

    Xét các trường hợp

    • (max_size1 ≠ max_size2) thì result = max_size1 - 1

      (loại bỏ đi một phần tử)

    • (max_size1 = max_size2)(pos_2 <= pos_1) thì result = max_size1 - 1

      (loại bỏ đi một phần tử chung của 2 đoạn con max_size1, max_size2)

    • (max_size1 = max_size2)(pos_2 > pos_1) thì result = max_size1

      (loại bỏ đi một phần tử của đoạn con max_size1 nhưng vẫn còn đoạn con max_size2)


    Reference Thuật Two-pointer | 100 điểm = AC | \(O(n)\) time | \(O(1)\) query | O(1) auxiliary space | Online Solving, Two-pointers

    C++
    int n = readInt();
    vector<int> a(n);
    for (int &x : a) cin >> x;
    
    int max_size1 = 0, max_size2 = 0;
    int  pos_1 = 0,  pos_2 = 0;
        for (int l = 0, r = 0; l < n; ++l) /// O(n)
        {
            while (r + 1 < n && a[l] + k > a[r + 1]) r++; /// Two-pointer
            int cur_size = r - l + 1;
    
             if (cur_size == max_size1) pos_2 = l, max_size2 = cur_size;
        else if (cur_size  > max_size1) pos_1 = r, max_size1 = cur_size;
    }
    cout << max_size1 - ((max_size1 != max_size2) || ((max_size1 == max_size2) && (pos_2 <= pos_1)));
    
    1 phản hồi

    • 4
      CQTshadow    2:12 p.m. 8 Tháng 6, 2020

      2 đoạn chứa max ở đây là 2 đoạn có size bằng max ấy hả bạn ?


      • 4
        CQTshadow    10:22 p.m. 7 Tháng 6, 2020

        Ai cho em xin solution với , cách deque bình thường xong lấy max( deque size) - 1 được có 57 / 100 điểm à :<

        • có lẽ Trường hợp trừ đi 1 chỉ là 1 TH nhỏ thôi
        2 phản hồi