最长上升子序列
我们讨论的是严格单调递增的LIS,然后考虑基本状态d p [ i ] dp[i] d p [ i ] 表示以i结尾的LIS长度。状态转移是d p i = max j < i , a j < a i d p j + 1 dp_i=\max\limits_{j<i, a_j<a_i} dp_j+1 d p i = j < i , a j < a i max d p j + 1
朴素O ( n 2 ) O(n^2) O ( n 2 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 void solve () { int n; cin >> n; vector<int > dp (n + 1 ) ; vector<int > a (n + 1 ) ; for (int i = 1 ; i <= n; i++) cin >> a[i]; for (int i = 1 ; i <= n; i++) { dp[i] = 1 ; for (int j = 1 ; j <= i - 1 ; j++) { if (a[j] < a[i]) dp[i] = max (dp[i], dp[j] + 1 ); } } int ans = *max_element (alls (dp)); cout << ans << endl; }
用树状数组优化求dp前缀最大值,我们开一个权值树状数组,c[i]表示以值i结尾的LIS长度,每次只需要先查询后更新即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 struct info { int x = 0 ; info operator +(const info &other) const { return {max (x, other.x)}; } }; void solve () { int n; cin >> n; vector<int > a (n + 1 ) ; for (int i = 1 ; i <= n; i++) cin >> a[i]; int ans = 0 ; Fwk<info> c (n) ; for (int i = 1 ; i <= n; i++) { int tmp = c.sum (a[i] - 1 ).x + 1 ; c.add (a[i], {tmp}); deb (i, a[i], tmp); ans = max (ans, tmp); } cout << ans << endl; }
当数组有比较大的时候我们使用离散化即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 struct info { int x = 0 ; info operator +(const info &other) const { return {max (x, other.x)}; } }; void solve () { int n; cin >> n; vector<int > a (n + 1 ) ; for (int i = 1 ; i <= n; i++) cin >> a[i]; vector<int > b; for (auto x : a) b.push_back (x); sort (alls (b)); b.erase (unique (alls (b)), b.end ()); auto find = [&](int x) { return lower_bound (alls (b), x) - b.begin () + 1 ; }; int ans = 0 ; Fwk<info> c (n) ; for (int i = 1 ; i <= n; i++) { int pos = find (a[i]); int tmp = c.sum (pos - 1 ).x + 1 ; c.add (pos, {tmp}); ans = max (ans, tmp); } cout << ans << endl; }
贪心加二分解决这个问题:维护一个vector,dp[i]表示长度为i 的LIS的结尾 元素的最小值 。 然后考虑如何转移:每次二分更新即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 void solve () { int n; cin >> n; vector<int > a (n + 1 ) , dp (n + 1 ) ; int len = 0 ; for (int i = 1 ; i <= n; i++) cin >> a[i]; dp[0 ]=-inf; for (int i = 1 ; i <= n; i++) { if (a[i] > dp[len]) { len++; dp[len] = a[i]; } else { int pos = lower_bound (dp.begin () + 1 , dp.begin () + len + 1 , a[i]) - dp.begin (); dp[pos] = a[i]; } } cout << len << endl; }