AtCoder Regular Contest 105 C(爆搜+线性dp + 二分) 题面 题解 代码

自己去at看吧, markdown复制是乱码

题解

就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;
}