กำหนดให้ แทนหมายเลขของนักกล้ามที่เดินเข้ายิมเป็นคนที่ และ คือจำนวนที่นักกล้ามตะโกนขณะที่นักกล้ามคนที่ กำลังเดินเข้ามาในยิม
กำหนดให้ฟังก์ชั่น เท่ากับจำนวนสมาชิกในเซต ที่มีค่าน้อยกว่าจำนวนเต็ม
ในข้อนี้ เราจะต้องหาลำดับของหมายเลขนักกล้ามที่เดินเข้ามาในยิม จากข้อมูลที่นักกล้ามแต่ละคนตะโกนเมื่อเดินเข้ายิม
หากนักกล้ามคนที่ ถึง ได้เดินเข้ามาในยิมเป็นที่เรียบร้อยแล้ว กำหนดให้ เป็นเซตของหมายเลขของนักกล้ามที่อยู่ในยิมแล้ว คนแรก จะได้ว่า เป็น และ สังเกตว่า และในกรณีนี้ เสมอ ดังนั้นจึงสรุปได้ว่า หรือ นั่นเอง
เมื่อเราทราบ เป็นที่เรียบร้อยแล้ว จะได้ว่า และ หรือ ดังนั้น
จากข้อสรุปด้านบน จึงเป็นจำนวนเต็ม ที่ทำให้ คุณสมบัติอย่างหนึ่งที่สามารถสังเกตได้ของฟังก์ชั่น คือ เมื่อ ดังนั้น เราจึงสามารถใช้การ Binary Search เพื่อหา ได้
สำหรับการหา เราจะใช้ Fenwick Tree โดยกำหนดให้ คือค่าของ Fenwick Tree ช่องที่ Fenwick Tree ประกอบไปด้วยสอง operation ได้แก่ update(i, k)
คือเพิ่มค่า ให้แก่ และ query(i)
คือจะคืนค่า โดยทั้งสอง operation ใช้เวลา ต่อการเรียก 1 ครั้ง
นิยามให้ จะเป็น 1 ก็ต่อเมื่อ และเป็น 0 เมื่อ ดังนั้น หรือ query(x - 1)
ทำให้เราสามารถ Binary Search หาจำนวนเต็ม ที่น้อยที่สุดที่ หรือ นั่งเอง เมื่อทราบค่า แล้ว เราก็ทำการลบ ออกจากเซต เพื่อเปลี่ยนจาก เป็น ด้วยการกำหนดให้ เป็น 0
เนื่องจาก Binary Search และ operation ของ Fenwick Tree ใช้เวลา จึงทำให้การหาค่า แต่ละค่า ใช้เวลา ซึ่งสามารถลดเวลาให้เหลือ ได้
โค้ดตัวอย่างดังนี้
#include <bits/stdc++.h> using namespace std; const int N = 5e5 + 5; int n, t[N]; int A[N], ans[N]; void update(int x, int k) { for (int i = x; i < N; i += i & -i) t[i] += k; } int query(int x, int ret = 0) { for (int i = x; i; i -= i & -i) ret += t[i]; return ret; } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", A + i), update(i, 1); for (int i = n; i; i--) { int l = 1, r = n; while (l < r) { int mid = (l + r) >> 1; if (query(mid) >= i - A[i]) r = mid; else l = mid + 1; } ans[i] = r; update(r, -1); } for (int i = 1; i <= n; i++) printf("%d ", ans[i]); printf("\n"); return 0; }
สำหรับโค้ดด้านบนนี้จะใช้เวลา
int pos = 0, x = i - A[i]; for (int j = 19; ~j; j--) if (pos + (1 << j) <= n && t[pos + (1 << j)] < x) x -= t[pos += (1 << j)]; ans[i] = pos + 1; update(pos + 1, -1);
สำหรับโค้ดด้านบนนี้เป็นการ Binary Search บน Fenwick Tree ภายในเวลา ทำให้ใช้เวลารวมแล้วเพียง เท่านั้น
เนื่องจาก constraint ของโจทย์มีค่าไม่มากพอ การ Binary Search ทั้งสองวิธีจึงผ่านทั้งคู่