题解:P12585 「KTSC 2019 R1」广播站
5 个 dp 数组的来了
首先,我们考虑如果一个广播站传播半径为
定向后,每个点的出度最多为
考虑最优化答案的情况下图的形态(建议手玩一下,感性理解也可以)。
如果存在 a<b<c<d,a\to c,d\to b
考虑
如果存在 a<b<c<d,c\to a,b\to d
- 若
dist_b\ne dist_c ,那么 类似地设x 为b,c 中dist 值较小的点,另一个点为y ,那么将y 指向x ,也一定不会变劣,且总代价会减小。因此这样的情况不会出现。 - 若
dist_b=dist_c ,则dist_a+1=dist_d+1 ,因此dist_a=dist_d 。此时c\to a,b\to d 就等价于b\to a,c\to d 。直接改为后者一定不会变劣,且总代价会减小。因此这样的情况不会出现。
如果存在 a<b<c<d,a\to c,b\to d
- 若
dist_c\le dist_d ,此时将b\to d 改为b\to c ,不会变劣,总代价减小。因此这样的情况不会出现。 - 若
dist_c>dist_d ,此时dist_c\ge dist_d+1=dist_b ,那么将a\to c 改为a\to b ,不会变劣,总代价减小。因此这样的情况不会出现。
如果存在 a<b<c<d,c\to a,d\to b
上面情况对称一下,同理。
因此,我们得出重要结论:不可能存在两条交叉(包含或共端点不算)的边,即不可能存在
同时,我们如果已经确定了汇点的位置,那么就不可能有边越过汇点连接,即不存在
这启发我们对于汇点两侧分别考虑,因为两侧之间互不影响。而数据范围可以让我们想到高次多项式时间复杂度,因此考虑 dp。在 dp 的过程中,我们发现可能整个序列前后缀的 dp 值与某一段非前后缀的 dp 值有关,因此考虑区间 dp。
设
l 的转移
定向后,一定存在
因此
r 的转移
同理,
L 的转移
同样地,设
那么
当
R 的转移
同理,
f 的转移
考虑对于
设
因此,不存在
时间复杂度
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 121;
int n, x[N], l[N][N][N], r[N][N][N];
int L[N][N][N], R[N][N][N], f[N][N][N];
inline int w(int a) { return a * a; }
void stations(vector <signed> X);
void answer(vector <int> Ans);
void stations(vector <signed> X) {
n = X.size();
for (int i = 1; i <= n; i++) x[i] = X[i - 1];
memset(l, 0x3f, sizeof(l)), memset(r, 0x3f, sizeof(r));
memset(f, 0x3f, sizeof(f)), memset(L, 0x3f,
sizeof(L)), memset(R, 0x3f, sizeof(R));
for (int i = 1; i <= n; i++)
for (int j = 0; j <= n; j++) l[i][i][j] = r[i][i][
j] = L[i][i][j] = R[i][i][j] = f[i][i][j] = 0;
for (int len = 2; len <= n; len++)
for (int i = 1; i + len - 1 <= n; i++) {
int j = i + len - 1;
if (len == 2) f[i][j][0] = 0;
for (int p = i; p < j; p++)
for (int k = 1; k <= len; k++)
f[i][j][k] = min(f[i][j][k],
l[i][p][k] + r[p + 1][j][k]);
for (int p = i; p < j; p++)
for (int k = 1; k <= len; k++)
L[i][j][k] = min(L[i][j][k], L[i][p][
k] + w(x[p] - x[i]) + f[p][j][k - 1]);
for (int p = i + 1; p <= j; p++)
for (int k = 1; k <= len; k++)
R[i][j][k] = min(R[i][j][k], R[p][j][
k] + w(x[j] - x[p]) + f[i][p][k - 1]);
for (int p = i + 1; p <= j; p++)
for (int k = 1; k <= len; k++)
l[i][j][k] = min(l[i][j][k], L[i][p][
k] + w(x[p] - x[i]) + l[p][j][k - 1]);
for (int p = i; p < j; p++)
for (int k = 1; k <= len; k++)
r[i][j][k] = min(r[i][j][k], r[i][p][
k - 1] + w(x[j] - x[p]) + R[p][j][k]);
for (int k = len + 1; k <= n; k++) l[i][j][k] =
l[i][j][k - 1], r[i][j][k] = r[i][j][k - 1],
L[i][j][k] = L[i][j][k - 1], R[i][j][k] =
R[i][j][k - 1], f[i][j][k] = f[i][j][k - 1];
}
vector <int> res(n - 1);
for (int i = 1; i < n; i++) {
int ans = 2e18;
for (int j = 1; j <= n; j++)
ans = min(ans, r[1][j][i] + l[j][n][i]);
res[i - 1] = ans;
}
answer(res);
}
:::