# [ACM训练] 斜率优化的dp问题

1iin

## 洛谷P3195 [HNOI2008]玩具装箱

### 解题报告

#### 解法一（TLE）

``````#include <iostream>
#include <algorithm>

typedef long long ll;

using namespace std;

const int N = 50010;
ll sumc[N], f[N], n, L;

int main() {
ll c;
for (int i = 1; i <= n; i++) {
sumc[i] = sumc[i - 1] + c;
}
for (int j = 1; j <= n; j++) {
f[j] = 0x3f3f3f3f3f3f3f3f;
for (int i = 0; i < j; i++) {
f[j] = min(f[j], f[i] + (j - i - 1 + sumc[j] - sumc[i] - L) * (j - i - 1 + sumc[j] - sumc[i] - L));
}
}
cout << f[n];
return 0;
}``````

#### 解法二（AC） 根据斜率优化

``f[j] = min(f[j], f[i] + (j - i - 1 + sumc[j] - sumc[i] - L) * (j - i - 1 + sumc[j] - sumc[i] - L));``

\$\$ a[i]=sumc[i]+i \$\$

\$\$ b[i]=sumc[i]+i+L+1 \$\$

\$\$ f[j] = f[i] + (a[j] - b[i]) ^ 2 \$\$

\$\$ f[i]+b[i]^2=2a[j]*b[i]-a[j]^2+f[j] \$\$

\$\$ y=2a[j]*x-a[j]^2+f[j] \$\$

2a[j] > 0，所以斜率大于0

``````#include <iostream>
#include <algorithm>

typedef long long ll;

using namespace std;

const int N = 50010;
ll sumc[N], f[N], n, L;
ll hh, tt, q[N];

ll A(ll i) {
return sumc[i] + i;
}

ll B(ll i) {
return (ll) sumc[i] + i + L + 1;
}

ll Y(ll i) {
return f[i] + B(i) * B(i);
}

ll X(ll i) {
return B(i);
}

double slope(ll i1, ll i2) {
return (double) (Y(i2) - Y(i1)) / (double) ((X(i2) - X(i1)));
}

int main() {
ll c;
hh = tt = 0;
for (int i = 1; i <= n; i++) {
sumc[i] = sumc[i - 1] + c;
}
for (int j = 1; j <= n; j++) {
while (hh < tt && Y(q[hh + 1]) - Y(q[hh]) < (X(q[hh + 1]) - X(q[hh])) * 2 * A(j)) {
hh++;
}
f[j] = f[q[hh]] + (A(j) - B(q[hh])) * (A(j) - B(q[hh]));
while (hh < tt && slope(j, q[tt - 1]) <= slope(q[tt], q[tt - 1])) {
tt--;
}
q[++tt] = j;
}
cout << f[n];
return 0;
}

``````

## P4072 [SDOI2016]征途

### 解题报告

#### 解法一

f[i] [j]表示走了i段现在在j地

``````#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>

typedef long long ll;

using namespace std;

const int N = 3010;
int n, m, sum[N];
ll f[N][N];

int main() {
for (int i = 1; i <= n; i++) {
int c;
sum[i] = sum[i - 1] + c;
}
memset(f, 0x3f, sizeof f);
f[0][0] = 0;
for (int i = 1; i <= m; i++) {
for (int j = 1; n - j >= m - i; j++) {
for (int k = 0; k < j; k++) {
f[i][j] = min(f[i][j], f[i - 1][k] + (sum[j] - sum[k]) * (sum[j] - sum[k]));
}
}
}
ll res = f[m][n] * m - sum[n] * sum[n];
cout << res;
return 0;
}

``````

#### 解法二

\$\$ f[i-1][k] + sum[k] ^2 = f[i,j] + 2* sum[j] * sum[k] - sum[j] ^2 \$\$

sum[k] = x

``````#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>

typedef long long ll;

using namespace std;

const int N = 3010;
int n, m, sum[N], q[N], hh, tt;
ll f[N][N];

ll X(int k) {
return sum[k];
}

ll Y(int i, int k) {
return f[i - 1][k] + sum[k] * sum[k];
}

double slope(int i, int k1, int k2) {
return (double) (Y(i, k1) - Y(i, k2)) / (double) (X(k1) - X(k2));
}

int main() {
for (int i = 1; i <= n; i++) {
int c;
sum[i] = sum[i - 1] + c;
}
memset(f, 0x3f, sizeof f);
for (int i = 1; i <= n; i++) {
f[1][i] = sum[i] * sum[i];
}
f[0][0] = 0;
for (int i = 2; i <= m; i++) {
hh = tt = 0;
for (int j = 1; n - j >= m - i; j++) {
while (hh < tt && slope(i, q[hh], q[hh + 1]) < 2 * sum[j]) {
hh++;
}
f[i][j] = f[i - 1][q[hh]] + (sum[j] - sum[q[hh]]) * (sum[j] - sum[q[hh]]);
while (hh < tt && slope(i, j, q[tt - 1]) <= slope(i, q[tt], q[tt - 1])) {
tt--;
}
q[++tt] = j;
}
}
ll res = f[m][n] * m - sum[n] * sum[n];
cout << res;
return 0;
}``````

## AcWing Q301 任务安排

### 解题报告

#### 解法一

``````#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>

typedef long long ll;

#define read(x, y) scanf("%d%d", &x, &y)

using namespace std;

const int N = 5010;
int n, s, sumt[N], sumc[N], f[N];

int main() {
for (int i = 1; i <= n; i++) {
int t, c;
sumt[i] = sumt[i - 1] + t;
sumc[i] = sumc[i - 1] + c;
}
for (int i = 1; i <= n; i++) {
f[i] = 0x3f3f3f3f;
for (int j = 0; j < i; j++) {
f[i] = min(f[i], f[j] + (sumc[n] - sumc[j]) * s + (sumc[i] - sumc[j]) * sumt[i]);
}
}
cout << f[n];
return 0;
}``````

#### 解法二

``````#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>

typedef long long ll;

#define read(x, y) scanf("%lld%lld", &x, &y)

using namespace std;

const int N = 300010;
ll n, s, sumt[N], sumc[N], f[N];
int hh, tt, q[N];

ll X(int i) {
return sumc[i];
}

ll Y(int i) {
return f[i];
}

double slope(int i1, int i2) {
return (double) (Y(i1) - Y(i2)) / (double) (X(i1) - X(i2));
}

int main() {
for (int i = 1; i <= n; i++) {
ll t, c;
sumt[i] = sumt[i - 1] + t;
sumc[i] = sumc[i - 1] + c;
}
for (int i = 1; i <= n; i++) {
while (hh < tt && slope(q[hh], q[hh + 1]) < s + sumt[i]) {
hh++;
}
f[i] = f[q[hh]] + (sumc[n] - sumc[q[hh]]) * s + (sumc[i] - sumc[q[hh]]) * sumt[i];
while (hh < tt && slope(i, q[tt - 1]) <= slope(q[tt], q[tt - 1])) {
tt--;
}
q[++tt] = i;
}
cout << f[n];
return 0;
}``````

Move on.

4 声望
3 粉丝
0 条评论