1. 程式人生 > >Educational Codeforces Round 34

Educational Codeforces Round 34

def first 狀壓 分析 最優 con push contest 一道

F - Clear The Matrix

分析

題目問將所有星變成點的花費,限制了行數(只有4行),就可以往狀壓DP上去靠了。
\(dp[i][j]\) 表示到第 \(i\) 列時狀態為 \(j\) 的花費,只需要記錄 16 位二進制,因為我們最多只能影響到 4 * 4 的星,那麽每次都是從一個 4 * 4 的矩陣轉移到一個 4 * 4 的矩陣,註意,轉移時必須保證最左邊列全部為 1 (即都是星號),那麽最後答案就是 \(dp[n][(1 << 16) - 1]\)
比如我們選定點 (i, j),將 3 * 3 的星變成點,那麽變的就是左上角 (i, j - 2) 右下角 (i + 2, j) 的這個矩陣。

為了狀態轉移,我們會同時對一列的星進行變換,可能有多種方案,這個可以預處理再加些優化,最後合法的是很少的。

code

#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
string mp[4];
int dp[2][1 << 16];
int n, cnt, a[5], b[133], c[133];
int calc(int xl, int xr, int yl, int yr) {
    int res = 0;
    for (int i = xl; i <= xr; i++) {
        for
(int j = yl; j <= yr; j++) { res += 1 << ((i * 4) + j); } } return res; } void dfs(int x, int mx, int st, int cost) { if (x == 4) { b[cnt] = st; c[cnt++] = cost; return; } for (int i = 4; i >= 1; i--) { if (x + i > 4
) continue; if (!x) { dfs(x + 1, i, st | calc(4 - i, 3, x, i - 1), cost + a[i]); } else { if (x + i > mx) { dfs(x + 1, x + i, st | calc(4 - i, 3, x, x + i - 1), cost + a[i]); } else { break; } } } dfs(x + 1, x, st, cost); } int main() { cin >> n >> a[1] >> a[2] >> a[3] >> a[4]; for (int i = 0; i < 4; i++) { cin >> mp[i]; } dfs(0, 0, 0, 0); memset(dp[0], 0x3f, sizeof dp[0]); dp[0][(1 << 16) - 1] = 0; int cur = 0; for (int i = 0; i < n; i++) { int cst = 0; for (int j = 0; j < 4; j++) { if (mp[j][i] == '.') { cst += 1 << (12 + j); } } cur = !cur; memset(dp[cur], 0x3f, sizeof dp[cur]); for (int j = 0; j < (1 << 12); j++) { dp[cur][j | cst] = dp[!cur][(j << 4) + 15]; if (dp[!cur][(j << 4) + 15] == 0x3f3f3f3f) continue; for (int k = 0; k < cnt; k++) { dp[cur][j | cst | b[k]] = min(dp[!cur][(j << 4) + 15] + c[k], dp[cur][j | cst | b[k]]); } } } cout << dp[cur][(1 << 16) - 1] << endl; return 0; }

G. Yet Another Maxflow Problem

分析

一道“網絡流”的題目。
本題主要註意最小割等於最大流,我們去構造這個解,即怎樣才算最小割。註意到本題邊的限制頗多,\(A_i\)-\(A_{i+1}\) 連有向邊,\(B_i\)-\(B_{i+1}\) 連有向邊,且從 A 到 B 連有向邊,考慮 A 這部分,如果刪掉邊 \(A_i\)-\(A_{i+1}\) ,那麽 \(A_{i+1}\) 下面所有邊都無意義了,對於 B 這部分,刪掉 \(B_i\)-\(B_{i+1}\),則 \(B_i\) 上面所有邊都無意義了,有這樣的性質後,我們枚舉左邊的邊,用線段樹維護刪掉右邊的邊的代價的最小值(右邊也有可能不刪),用 multiset 維護全局最優解。

code

#include <bits/stdc++.h>
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
using namespace std;
const int N = 2e5 + 10;
int a[N], b[N];
vector<pair<int, int> > G[N];
long long s[N << 4], lazy[N << 4];
void pushDown(int rt) {
    lazy[rt << 1] += lazy[rt];
    lazy[rt << 1 | 1] += lazy[rt];
    s[rt << 1] += lazy[rt];
    s[rt << 1 | 1] += lazy[rt];
    lazy[rt] = 0;
}
void pushUp(int rt) { s[rt] = min(s[rt << 1], s[rt << 1 | 1]); }
void build(int l, int r, int rt) {
    if (l == r)
        s[rt] = b[l - 1];
    else {
        int m = l + r >> 1;
        build(lson);
        build(rson);
        pushUp(rt);
    }
}
void update(int L, int R, int c, int l, int r, int rt) {
    if (l >= L && r <= R) {
        lazy[rt] += c;
        s[rt] += c;
    } else {
        pushDown(rt);
        int m = l + r >> 1;
        if (m >= L) update(L, R, c, lson);
        if (m < R) update(L, R, c, rson);
        pushUp(rt);
    }
}
long long query(int L, int R, int l, int r, int rt) {
    if (l >= L && r <= R)
        return s[rt];
    else {
        pushDown(rt);
        int m = l + r >> 1;
        long long res = (1LL << 62);
        if (m >= L) res = query(L, R, lson);
        if (m < R) res = min(res, query(L, R, rson));
        pushUp(rt);
        return res;
    }
}
multiset<long long> mset;
long long cb[N];
int main() {
    int n, m, q;
    cin >> n >> m >> q;
    for (int i = 1; i < n; i++) {
        scanf("%d%d", &a[i], &b[i]);
    }
    for (int i = 0; i < m; i++) {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        G[u].push_back(pair<int, int>(v, w));
    }
    build(1, n, 1);
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j < G[i].size(); j++) {
            update(1, G[i][j].first, G[i][j].second, 1, n, 1);
        }
        cb[i] = s[1];
        mset.insert(cb[i] + a[i]);
    }
    printf("%I64d\n", *mset.begin());
    while (q--) {
        int v, w;
        scanf("%d%d", &v, &w);
        mset.erase(mset.lower_bound(a[v] + cb[v]));
        a[v] = w;
        mset.insert(w + cb[v]);
        printf("%I64d\n", *mset.begin());
    }
    return 0;
}

Educational Codeforces Round 34