โจทย์ต้องการให้เราหา ลำดับลด (Decreasing Subsequence) ที่มีความยาว จากลำดับความยาว ที่กำหนดมาให้
Dynamic Programming
นิยาม = จำนวน ลำดับลด ( Decreasing Subsequence ) ที่มีความยาว ตัวและลงท้ายด้วย ของลำดับ ตัวแรก
สมมุติว่าปัจจุบัน เรากำลังพิจารณาลำดับ ตัวแรก การ transition จาก ของลำดับ ตัวแรก สามารถทำได้โดยการเพิ่มจำนวนวิธีที่เรานำ มาต่อท้ายลำดับลดก่อนหน้านี้ทุกลำดับที่ลงท้ายด้วยตัวเลขที่มีค่ามากกว่า เข้าไปใน ของลำดับ ตัวแรก หรือก็คือ
คำตอบของปัญหาที่เราต้องการ คือ ลำดับลดความยาว หรือก็คือ นั่นเอง เราสามารถคำนวณคำตอบของปัญหาด้วยวิธีนี้ได้ในเวลา
Fenwick Tree
สังเกตว่าวิธีที่กล่าวมามีปัญหาคือเราต้องพิจารณาทุก ที่ ซึ่งใช้เวลาได้มากถึง
หากเราเปลี่ยนตาราง ให้เป็นโครงสร้างของต้น Fenwick Tree ได้ เราจะสามารถหาลำดับลดทุกลำดับที่ลงท้ายด้วยตัวเลขที่มีค่ามากกว่า ได้ในเวลา โดยที่เราไม่ต้องพิจารณาทุก
ปัญหาต่อมาคือ เราต้องนำจำนวนวิธีของลำดับทั้งหมดใน มายัง ด้วย แต่เราสามารถแก้ปัญหานี้ได้ด้วยการใช้ ตาราง เดิม ไปเลย
Time Complexity :
Space Complexity :
Code :
#include <bits/stdc++.h> using namespace std; const int mod = 999999999; const int N = 80003, K = 42; int mul(int a, int b) { return a * 1ll * b % mod; } int add(int a, int b) { int c = a + b; if (c >= mod) return c - mod; return c; } int dp[K][N], n; void update(int k, int l, int val) { // fenwick(dp) update for (int i = l; i <= n; i += (i & -i)) dp[k][i] = add(dp[k][i], val); } int query(int k, int l) { // fenwick(dp) query int sum = 0; for (int i = l; i > 0; i -= (i & -i)) sum = add(sum, dp[k][i]); return sum; } int a[N]; int main() { int k; scanf("%d %d", &n, &k); for (int i = 1; i <= n; ++i) scanf("%d", &a[i]); // transition for (int i = 1; i <= n; ++i) { for (int j = k; j >= 2; --j) { update(j, a[i], add(query(j - 1, n), mod - query(j - 1, a[i]))); } update(1, a[i], 1); } printf("%d\n", query(k, n)); return 0; }