Skip to content

Commit d79e3ea

Browse files
authored
Update Lagrange.mdx
Changed code and updated explanation to make everything align with the dp transitions
1 parent a51860c commit d79e3ea

File tree

1 file changed

+36
-42
lines changed

1 file changed

+36
-42
lines changed

content/6_Advanced/Lagrange.mdx

+36-42
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ This idea almost works but there are still some very important caveats and condi
7474

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

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 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.
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 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 the sum by. We can intuitively see that this is true.
7878

7979
<Spoiler title="Proof that our function is concave">
8080

@@ -99,15 +99,16 @@ Consider the following graphs of $f(x)$ and $f(x)-\lambda x$. In this example, w
9999
frameborder="0"
100100
/>
101101

102-
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.
102+
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**.
103103

104-
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.
104+
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(\lambda)$ to be the **maximal** number of subarrays to achieve $v(\lambda)$). 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$. So $v(\lambda)$ will be the **maximum** of $f(x) - \lambda x$ and $c(\lambda)$ will equal to the rightmost $x$ that **maximizes** $f(x) - \lambda x$.
107107

108-
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).
108+
Given the shape of $f(x) - \lambda x$, we know that $f(x) - \lambda x$ will be maximized at all points where $\lambda$ is equal to the slope of $f(x)$ (these points are red in the graph above). If there are no such points it will be maximized at the rightmost point where the slope is less than $\lambda$. So this means that $c(\lambda)$ will be the rightmost $x$ at which the slope of $f(x)$ is still greater or equal to $\lambda$.
109109

110-
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).
110+
111+
Now we know exactly what $\lambda$ represents: $\lambda$ is the slope and $c(\lambda)$ is the rightmost $x$ at which the slope of $f(x)$ is still greater or equal to $\lambda$.
111112

112113
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}}$ in that case.
113114

@@ -119,49 +120,42 @@ using namespace std;
119120

120121
#define ll long long
121122

122-
const int MAX = 3e5 + 5;
123-
124-
int n, k, A[MAX];
125-
pair<ll, ll> dp[MAX][2];
126-
127-
pair<ll, ll> better(pair<ll, ll> a, pair<ll, ll> b) {
128-
if (a.first == b.first) return (a.second < b.second ? a : b);
129-
130-
return (a.first > b.first ? a : b);
131-
}
132-
133-
bool solve(ll lmb) {
134-
dp[0][0] = {0, 0};
135-
dp[0][1] = {-1e18, 0};
136-
137-
for (int i = 1; i <= n; i++) {
138-
dp[i][0] = better(dp[i - 1][0], dp[i - 1][1]);
139-
140-
dp[i][1] =
141-
better({dp[i - 1][0].first + A[i] - lmb, dp[i - 1][0].second + 1},
142-
{dp[i - 1][1].first + A[i], dp[i - 1][1].second});
143-
}
144-
return better(dp[n][0], dp[n][1]).second <= k;
123+
const int MAX = 300000;
124+
const ll INF = (ll)300000 * 1000000000;
125+
126+
int n, k, A[MAX + 1];
127+
pair<ll, ll> dp[MAX + 1][2];
128+
129+
pair<ll, ll> solveLambda(ll lmb){
130+
dp[0][0] = {0, 0};
131+
dp[0][1] = {-INF, 0};
132+
133+
for (int i = 1; i <= n; i++){
134+
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1]);
135+
136+
dp[i][1] = max(
137+
make_pair(dp[i - 1][0].first + A[i] - lmb, dp[i - 1][0].second + 1),
138+
make_pair(dp[i - 1][1].first + A[i], dp[i - 1][1].second)
139+
);
140+
}
141+
return max(dp[n][0], dp[n][1]);
145142
}
146143

147-
int main() {
148-
ios_base::sync_with_stdio;
149-
cin.tie(0);
150-
cin >> n >> k;
144+
int main(){
145+
cin >> n >> k;
151146

152-
for (int i = 1; i <= n; i++) cin >> A[i];
147+
for (int i = 1; i <= n; i++) cin >> A[i];
153148

154-
ll L = 0, H = 1e15;
149+
ll lo = 0, hi = INF;
155150

156-
while (L < H) {
157-
ll M = (L + H) / 2;
158-
solve(M) ? H = M : L = M + 1;
159-
}
160-
solve(L);
161-
162-
cout << better(dp[n][0], dp[n][1]).first + L * k << "\n";
151+
while (lo < hi){
152+
ll M = (lo + hi) / 2;
153+
solveLambda(M).second <= k ? hi = M : lo = M + 1;
154+
}
155+
cout << solveLambda(lo).first + lo * k << endl;
163156
}
164157
```
158+
165159
## Problems
166160
167161
<Problems problems="probs" />

0 commit comments

Comments
 (0)