[CF321E] Ciel and Gondolas - 决策单调性dp
Description
有 n 个人在队列里,有 k 条船,第 i 条船到时,前若干个人可以上船。最后一条船将载走所有的人。第 i 个人和第 j 个人处在同一条船上会产生 uij 的沮丧值,求出最小的沮丧值和。(n le 4000, k le 800)
Solution
O(nnk) 的 dp 是显然的,由于满足四边形不等式,具有决策单调性
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 4005;
int n, m, f[N][N], s[N][N], p[N][N];
inline int read()
{
int x = 0;
bool t = false;
char ch = getchar();
while ((ch < '0' || ch > '9') && ch != '-')
ch = getchar();
if (ch == '-')
t = true, ch = getchar();
while (ch <= '9' && ch >= '0')
x = x * 10 + ch - 48, ch = getchar();
return t ? -x : x;
}
signed main()
{
n = read();
m = read();
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
s[i][j] = read();
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
memset(f, 0x3f, sizeof f);
for (int i = 0; i <= m; i++)
f[0][i] = 0, p[n + 1][i] = n - 1;
for (int j = 1; j <= m; j++)
for (int i = n; i >= 1; i--)
for (int k = p[i][j - 1]; k <= p[i + 1][j]; k++)
{
int tmp = f[k][j - 1] + (s[i][i] + s[k][k] - s[i][k] - s[k][i]) / 2;
if (tmp <= f[i][j])
f[i][j] = tmp, p[i][j] = k;
}
cout << f[n][m] << endl;
}