Skip to content

Commit aacd1a3

Browse files
authored
Update Lagrange.mdx
1 parent 892e4a8 commit aacd1a3

File tree

1 file changed

+135
-6
lines changed

1 file changed

+135
-6
lines changed

content/6_Advanced/Lagrange.mdx

+135-6
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
---
22
id: lagrange
33
title: 'Lagrangian Relaxation'
4-
author: Benjamin Qi
4+
author: Benjamin Qi, Alex Liang, Dong Liu
55
description: 'aka Aliens Trick'
66
prerequisites:
77
- convex-hull
88
frequency: 1
99
---
1010

11-
adding lambda\*smth
12-
13-
<Problems problems="sample" />
14-
15-
## Tutorial
11+
## Resources
1612

1713
<Resources>
1814
<Resource
@@ -27,6 +23,139 @@ adding lambda\*smth
2723
/>
2824
</Resources>
2925

26+
## Lagrangian Relaxation
27+
28+
Lagrangian Relaxation involves transforming a constraint on a variable into a cost $\lambda$ and binary searching for the optimal $\lambda$.
29+
30+
<FocusProblem problem="sample" />
31+
32+
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.
33+
34+
### Intuition
35+
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.
37+
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$).
39+
40+
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.
41+
42+
<Spoiler title="Dynamic Programming Solution">
43+
Let's have $\texttt{dp}[i][j:\{0,1\}]$ represent the maximum sum if we consider the first $i$ elements, given that $j=0/1$ implies whether
44+
element $i$ is part of a subarray. Let $\texttt{cnt}[i][j]$ represent the number of
45+
people used in an optimal arrangement of $\texttt{dp}[i][j]$.
46+
47+
For our $\texttt{dp}$ transitions, we have
48+
49+
$$
50+
\{\texttt{dp}[i][0], \texttt{cnt}[i][0]\} =
51+
\max\begin{cases} \{\texttt{dp}[i - 1][0], \texttt{cnt}[i - 1][0]\}\\
52+
\{\texttt{dp}[i - 1][1], \texttt{cnt}[i - 1][1]\}
53+
\end{cases}
54+
$$
55+
56+
and
57+
58+
$$
59+
\{\texttt{dp}[i][1], \texttt{cnt}[i][1]\} =
60+
\max\begin{cases}\{\texttt{dp}[i - 1][0] + A[i] - \lambda, \texttt{cnt}[i - 1][0] + 1\}\\
61+
\{\texttt{dp}[i - 1][1] + A[i], \texttt{cnt}[i - 1][1]\}\end{cases}
62+
$$
63+
64+
because we either begin a new subarray or we continue an existing subarray.
65+
</Spoiler>
66+
67+
Let $v$ be the maximal achievable sum with $\lambda$ penalty and $c$ be the number of subarrays used to achieve $v$. Then the **maximal possible sum achievable if we use exactly $c$ subarrays is $v+\lambda c$**. Note that we add $\lambda c$ to undo the penalty.
68+
69+
Our goal is to find some $\lambda$ such that $c=k$. As we increase $\lambda$, it makes sense for $c$ to decrease since we are penalizing subarrays more. Thus, we can try to binary search for $\lambda$ to make $c=k$ and set our answer to be $v+\lambda c$ at the optimal $\lambda$.
70+
71+
This idea almost works but there are still some very important caveats and conditions that we have not considered.
72+
73+
### Geometry
74+
75+
Let $f(x)$ be the maximal sum if we use at most $x$ subarrays. We want to find $f(K)$.
76+
77+
The first condition is that $f(x)$ **must be concave or convex**. Since $f(x)$ is increasing in this problem, the means that we want $f(c)$ to be concave: $f(x) - f(x - 1) \ge f(x + 1) - f(x)$. Intuitively speaking, this means that the more subarrays we add, the less we increase our answer by.
78+
79+
<Spoiler title="Proof that our function is concave">
80+
81+
</Spoiler>
82+
83+
Consider the following graphs of $f(x)$ and $f(x)-\lambda x$. In this example, we have $\lambda=5$.
84+
85+
<iframe
86+
src="https://www.desmos.com/calculator/ydynwc2fej?embed"
87+
width="500px"
88+
height="300px"
89+
frameborder="0"
90+
/>
91+
92+
Here is where the fact that $f(x)$ is concave comes in. Because the slope is non-increasing, we know that $f(x) - \lambda x$ will first increase, then stay the same, and finally decrease.
93+
94+
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.
95+
96+
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$**.
97+
98+
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).
99+
100+
Now we know exactly what $\lambda$ represents: $\lambda$ is the slope and $c(\lambda)$ is the position with slope equal to $\lambda$ (if there are multiple such positions then $c(\lambda)$ is the leftmost one).
101+
102+
We binary search for $\lambda$ and find the highest $\lambda$ such that $c(\lambda) \le K$. Let the optimal value be $\lambda_{\texttt{opt}}$. Then our answer is $v(\lambda_{\texttt{opt}}) + \lambda_{\texttt{opt}} K$. Note that this works even if $c(\lambda_{\texttt{opt}}) \neq K$ since $c(\lambda_{\texttt{opt}})$ and $K$ will be on the same line with slope $\lambda_{\texttt{opt}}$.
103+
104+
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.
105+
106+
```cpp
107+
#include <bits/stdc++.h>
108+
using namespace std;
109+
110+
#define ll long long
111+
#define pll pair<ll, ll>
112+
#define f first
113+
#define s second
114+
115+
const int MAX = 3e5 + 5;
116+
117+
int n, k, A[MAX]; pll dp[MAX][2];
118+
119+
pll better(pll a, pll b){
120+
if (a.f == b.f)
121+
return (a.s < b.s ? a : b);
122+
123+
return (a.f > b.f ? a : b);
124+
}
125+
126+
bool solve(ll lmb){
127+
dp[0][0] = {0, 0};
128+
dp[0][1] = {-1e18, 0};
129+
130+
for (int i = 1; i <= n; i++){
131+
dp[i][0] = better(dp[i - 1][0], dp[i - 1][1]);
132+
133+
dp[i][1] = better(
134+
{dp[i - 1][0].f + A[i] - lmb, dp[i - 1][0].s + 1},
135+
{dp[i - 1][1].f + A[i], dp[i - 1][1].s}
136+
);
137+
}
138+
return better(dp[n][0], dp[n][1]).s <= k;
139+
}
140+
141+
int main(){
142+
ios_base::sync_with_stdio; cin.tie(0);
143+
cin >> n >> k;
144+
145+
for (int i = 1; i <= n; i++)
146+
cin >> A[i];
147+
148+
ll L = 0, H = 1e15;
149+
150+
while (L < H){
151+
ll M = (L + H) / 2;
152+
solve(M) ? H = M : L = M + 1;
153+
}
154+
solve(L);
155+
156+
cout<<better(dp[n][0], dp[n][1]).f + L * k<<"\n";
157+
}
158+
```
30159
## Problems
31160
32161
<Problems problems="probs" />

0 commit comments

Comments
 (0)