ABC225G X

X


看到题,dp?no。

如果想要 dp,至少要知道三个方向上的情况,不管什么顺序都很难 dp。

看到如同我的智商一样低的数据范围,很像 wll。

选一些物品使得代价最大,还有额外代价,考虑最小割,先把每个点向 \(\texttt{T}\) 连价值为 \(a_{i, j}\) 的边如果这些边被割即代表不要这个格子了。

那么 \(\texttt{S}\) 那边怎么连边,我们实际上是在求各个方向上的连通块个数,这个限制太全局了,把它放到每个点上,单独考虑一个方向上的情况。

如果一个点的前驱不选,而它选了,则带来 \(C\) 的贡献,把它视作连通块的起点。而如果前面有一个起点,中间的点都划了另一个方向上的边,它就可以免费划线。

具体来说,对应到网络流上就是:左上和右上向该点连边,如果没有点就从 \(\texttt{S}\) 连边,代价都为 \(C\)。割掉连向该点的一条边对应把它作为某个方向上的起点。能否免费划线的限制恰好与最小割的限制相同。

//        No mind to think.
//
//        No will to break.
//
//        No voice to cry suffering.
//
//        Born of God and Void.
//
//        You shall seal the blinding light that plagues their dreams.
//
//        You are the Vessel.
//
//        You are the Hollow Knight.
#ifdef N2
#define _GLIBCXX_DEBUG
#define LOG(...) fprintf(stderr, __VA_ARGS__)
#define DO(...) __VA_ARGS__
#else 
#define LOG(...) void(0)
#define DO(...) void(0)
#define NDEBUG
#endif
#define syncoff ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
using ll = long long;
int dis[maxn];
int S = maxn - 2, T = maxn - 1;
struct Edge {
    int v, rev;
    ll flow;
    Edge() = default;
    Edge(int v, ll flow, int rev) : v(v), flow(flow), rev(rev) {}
};
vector<Edge> G[maxn];
int cur[maxn];
void Add(int u, int v, ll w) {
//        cerr << u << ' ' << v << ' ' << w << '\n';
    G[u].emplace_back(v, w, G[v].size());
    G[v].emplace_back(u, 0, G[u].size() - 1);
}
bool Bfs() {
    memset(dis, 0, sizeof(dis));
    queue<int> q;
    dis[S] = 1;
    q.emplace(S);
    while(!q.empty()) {
        int u = q.front(); q.pop();
        for(auto e : G[u]) {
            if(dis[e.v] || !e.flow) continue;
            dis[e.v] = dis[u] + 1;
            q.emplace(e.v);
        }
    }
    return dis[T];
}
ll Dfs(int u, ll in) {
    if(u == T) return in;
    ll out = 0;
    for(int &i = cur[u]; i < G[u].size(); i++) {
        auto &e = G[u][i];
        if(dis[e.v] != dis[u] + 1 || !e.flow) continue;
        int del = Dfs(e.v, min(e.flow, in - out));
        e.flow -= del, G[e.v][e.rev].flow += del;
        out += del;
        if(in == out) break;
    }
    return out;
}
ll Dinic() {
    ll res = 0;
    while(Bfs()) {
        memset(cur, 0, sizeof(cur));
        res += Dfs(S, 0x3f3f3f3f3f3f3f3f);
    }
    return res;
}
const int maxl = 110;
int a[maxl][maxl];
ll sum;
int n, m, c;
bool In(int x, int y) {
    return x > 0 && x <= n && y > 0 && y <= m;
}
int Map(int x, int y) {
    return (x - 1) * m + y;
}
int main() {
    cin >> n >> m >> c;
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            cin >> a[i][j];
            sum += a[i][j];
            Add(Map(i, j), T, a[i][j]);
            if(In(i - 1, j - 1)) Add(Map(i - 1, j - 1), Map(i, j), c);
            else Add(S, Map(i, j), c);
            if(In(i - 1, j + 1)) Add(Map(i - 1, j + 1), Map(i, j), c);
            else Add(S, Map(i, j), c);
        }
    }
    cout << sum - Dinic();
}
posted @ 2023-11-08 19:37  N2MENT  阅读(13)  评论(0)    收藏  举报