AtCoder Regular Contest 105 C(爆搜+线性dp + 二分)
题面
题解
就8只骆驼, 数据量很小, 要么高维dp, 要么爆搜
这里选择 爆搜(反正 8! 没多少) + dp
暴力去全排列 骆驼的顺序, 然后算每次排序后 的 距离, 每次min一下
对于给定的顺序的骆驼
必定每一段 i 到 j, 这段序列能通过任意桥而不把桥摧毁, 这样我们就有了 dis[i][j], 表示 i 到 j 不压塌桥的 i 到 j 的最短距离
这样就可以 dp 了, f[i] 表示 1 到 i 的最短距离, 那不就是 f[i] = max(f[j] + dis[j][i]) 吗
取max 是是的区间合理化, 相当于 dis[i][j] = min(dis[i][k] + dis[k][k + 1] + dis[k + 1][j])
那么现在问题转换成了怎么求 dis[i][j]
说白了就是 找到所有 称重量 小于 sum[i][j](i~j 骆驼重量和) 的桥 中 最长的距离
发现了吧? (按桥的长度先排个序, 在用 mi[i] 表示 i ~ n 桥的最小称重量)排个序, 二分就行了
代码
const int N = 1e5 + 5;
int n, m, _, k;
ll ans = 2e9, dis[9];
int b[9], mi[N];
int s[9][9], d[9][9];
PII a[N];
bool v[9];
ll check() {
rep (j, 2, n) rep (i, 1, n - j + 1) s[i][j + i - 1] = s[i][i + j - 2] + s[i + j - 1][i + j - 1];
rep (i, 1, n) rep (j, i + 1, n) d[i][j] = a[lower_bound(mi + 1, mi + 1 + m, s[i][j]) - mi - 1].fi;
rep (i, 1, n) dis[i] = 0;
rep (i, 1, n) rep (j, 1, i - 1) umax(dis[i], dis[j] + d[j][i]);
return dis[n];
}
void dfs(int cur) {
if (cur == n + 1) { umin(ans, check()); return; }
rep (i, 1, n) {
if (v[i]) continue;
s[cur][cur] = b[i]; v[i] = 1;
dfs(cur + 1); v[i] = 0;
}
}
int main() {
IOS; cin >> n >> m;
rep (i, 1, n) cin >> b[i];
rep (i, 1, m) cin >> a[i].fi >> a[i].se;
sort(a + 1, a + 1 + m); mi[m] = a[m].se;
per (i, m - 1, 1) mi[i] = min(mi[i + 1], a[i].se);
rep (i, 1, n) if (b[i] > mi[1]) { cout << -1; return 0; }
dfs(1); cout << ans;
return 0;
}