Skip to content

Commit db701f1

Browse files
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
1 parent 1ef0c82 commit db701f1

File tree

1 file changed

+42
-44
lines changed

1 file changed

+42
-44
lines changed

content/6_Advanced/Lagrange.mdx

+42-44
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,17 @@ frequency: 1
2525

2626
## Lagrangian Relaxation
2727

28-
Lagrangian Relaxation involves transforming a constraint on a variable into a cost $\lambda$ and binary searching for the optimal $\lambda$.
28+
Lagrangian Relaxation involves transforming a constraint on a variable into a cost $\lambda$ and binary searching for the optimal $\lambda$.
2929

3030
<FocusProblem problem="sample" />
3131

3232
The problem gives us a length $N$ ($1 \le N \le 3 \cdot 10^5$) array of integers in the range $[-10^9,10^9]$. We are given some $K$ ($1 \le K \le N$) and are asked to choose at most $K$ disjoint subarrays such that the sum of elements included in a subarray is maximized.
3333

3434
### Intuition
3535

36-
The main bottleneck of any dynamic programming solution to this problem is having to store the number of subarrays we have created so far.
36+
The main bottleneck of any dynamic programming solution to this problem is having to store the number of subarrays we have created so far.
3737

38-
Let's try to find a way around this. Instead of storing the number of subarrays we have created so far, we assign a penalty of $\lambda$ for creating a new subarray (i.e. everytime we create a subarray we penalize our sum by $\lambda$).
38+
Let's try to find a way around this. Instead of storing the number of subarrays we have created so far, we assign a penalty of $\lambda$ for creating a new subarray (i.e. everytime we create a subarray we penalize our sum by $\lambda$).
3939

4040
This leads us to the sub-problem of finding the maximal sum and number of subarrays used if creating a new subarray costs $\lambda$. We can solve this in $\mathcal{O}(N)$ time with dynamic programming.
4141

@@ -72,7 +72,7 @@ This idea almost works but there are still some very important caveats and condi
7272

7373
### Geometry
7474

75-
Let $f(x)$ be the maximal sum if we use at most $x$ subarrays. We want to find $f(K)$.
75+
Let $f(x)$ be the maximal sum if we use at most $x$ subarrays. We want to find $f(K)$.
7676

7777
The first condition is that $f(x)$ **must be concave or convex**. Since $f(x)$ is increasing in this problem, the means that we need $f(x)$ to be concave: $f(x) - f(x - 1) \ge f(x + 1) - f(x)$. In other words, this means that the more subarrays we add, the less we increase our answer by. We can intuitively see that this is true.
7878

@@ -103,7 +103,7 @@ Here is where the fact that $f(x)$ is concave comes in. Because the slope is non
103103

104104
Let $v(\lambda)$ be the optimal maximal achievable sum with $\lambda$ penalty and $c(\lambda)$ be the number of subarrays used to achieve $v(\lambda)$ (note that if there are multiple such possibilities, we set $c$ to be the **minimal** number of subarrays to achieve $v$). These values can be calculated in $\mathcal{O}(N)$ time using the dynamic programming approach described above.
105105

106-
When we assign the penalty of $\lambda$, we are trying to find the maximal sum if creating a subarray reduces our sum by $\lambda$. In other words, **we are trying to find the maximum of $f(x) - \lambda x$**.
106+
When we assign the penalty of $\lambda$, we are trying to find the maximal sum if creating a subarray reduces our sum by $\lambda$. In other words, **we are trying to find the maximum of $f(x) - \lambda x$**.
107107

108108
Without loss of generality, suppose there exists a slope equal to $\lambda$. Given the shape of $f(x) - \lambda x$, we know that $f(x) - \lambda x$ will be maximized at the points where $\lambda$ is equal to the slope of $f(x)$ (these points are red in the graph above). This means that $c(\lambda)$ will be the point at which $\lambda$ is equal to the slope of $f(x)$ (if there are multiple such points, then $c(\lambda)$ will be the leftmost one).
109109

@@ -113,57 +113,55 @@ We binary search for $\lambda$ and find the highest $\lambda$ such that $c(\lamb
113113

114114
Because calculating $v(\lambda)$ and $c(\lambda)$ with the dynamic programming solution described above will take $\mathcal{O}(N)$ time, this solution runs in $\mathcal{O}(N\log{\sum A[i]})$ time.
115115

116-
```cpp
116+
```cpp
117117
#include <bits/stdc++.h>
118118
using namespace std;
119-
119+
120120
#define ll long long
121121
#define pll pair<ll, ll>
122122
#define f first
123123
#define s second
124-
124+
125125
const int MAX = 3e5 + 5;
126126

127-
int n, k, A[MAX]; pll dp[MAX][2];
128-
129-
pll better(pll a, pll b){
130-
if (a.f == b.f)
131-
return (a.s < b.s ? a : b);
127+
int n, k, A[MAX];
128+
pll dp[MAX][2];
129+
130+
pll better(pll a, pll b) {
131+
if (a.f == b.f) return (a.s < b.s ? a : b);
132132

133-
return (a.f > b.f ? a : b);
133+
return (a.f > b.f ? a : b);
134134
}
135135

136-
bool solve(ll lmb){
137-
dp[0][0] = {0, 0};
138-
dp[0][1] = {-1e18, 0};
139-
140-
for (int i = 1; i <= n; i++){
141-
dp[i][0] = better(dp[i - 1][0], dp[i - 1][1]);
142-
143-
dp[i][1] = better(
144-
{dp[i - 1][0].f + A[i] - lmb, dp[i - 1][0].s + 1},
145-
{dp[i - 1][1].f + A[i], dp[i - 1][1].s}
146-
);
147-
}
148-
return better(dp[n][0], dp[n][1]).s <= k;
136+
bool solve(ll lmb) {
137+
dp[0][0] = {0, 0};
138+
dp[0][1] = {-1e18, 0};
139+
140+
for (int i = 1; i <= n; i++) {
141+
dp[i][0] = better(dp[i - 1][0], dp[i - 1][1]);
142+
143+
dp[i][1] = better({dp[i - 1][0].f + A[i] - lmb, dp[i - 1][0].s + 1},
144+
{dp[i - 1][1].f + A[i], dp[i - 1][1].s});
145+
}
146+
return better(dp[n][0], dp[n][1]).s <= k;
149147
}
150-
151-
int main(){
152-
ios_base::sync_with_stdio; cin.tie(0);
153-
cin >> n >> k;
154-
155-
for (int i = 1; i <= n; i++)
156-
cin >> A[i];
157-
158-
ll L = 0, H = 1e15;
159-
160-
while (L < H){
161-
ll M = (L + H) / 2;
162-
solve(M) ? H = M : L = M + 1;
163-
}
164-
solve(L);
165-
166-
cout << better(dp[n][0], dp[n][1]).f + L * k << "\n";
148+
149+
int main() {
150+
ios_base::sync_with_stdio;
151+
cin.tie(0);
152+
cin >> n >> k;
153+
154+
for (int i = 1; i <= n; i++) cin >> A[i];
155+
156+
ll L = 0, H = 1e15;
157+
158+
while (L < H) {
159+
ll M = (L + H) / 2;
160+
solve(M) ? H = M : L = M + 1;
161+
}
162+
solve(L);
163+
164+
cout << better(dp[n][0], dp[n][1]).f + L * k << "\n";
167165
}
168166
```
169167
## Problems

0 commit comments

Comments
 (0)