Loading

P7730 [JDWOI-1] 蜀道难 题解

思路

考虑费用流。

发现区间操作与单调不降。

考虑差分。

\(a_i=h_i-h_{i-1}\)

那么我们需要让所有的 \(a_i\) 全部都变为自然数。

考虑一次区间操作的影响。

对于 \((+,l,r)\),我们会让 \(a_l\) 加一,\(a_{r+1}\) 减一。

对于 \((-,l,r)\),我们会让 \(a_l\) 减一,\(a_{r+1}\) 加一。

那么我们可以建出以下费用流模型。

对于 \(a_i>0\),连 \((s,i,a_i,0)\),表示可以减 \(a_i\) 次。

对于 \(a_i<0\),连 \((i,t,-a_i,0)\),表示必须加 \(-a_i\) 次。

可以连 \((s,n+1,inf,0)\) 补充流量。

对于 \((+,l,c)\),每一个点连 \((i,i-l,inf,c)\)

对于 \((-,l,c)\),每一个点连 \((i,i+l,inf,c)\)

然后跑费用流即可。

当然,值得一提的是,注:所有时候山的高度都不能为负,所以 \(h_0=0\)

Code

/*
  ! 如果没有天赋,那就一直重复
  ! Created: 2024/06/03 14:23:49
*/
#include <bits/stdc++.h>
using namespace std;

#define fro(i, x, y) for (int i = (x); i <= (y); i++)
#define pre(i, x, y) for (int i = (x); i >= (y); i--)

struct NetWork {
  using i64 = long long;
  struct edge { int to, nxt; i64 v, c; };
  int ct, n, s, t; i64 mf, mc;
  vector<int> dp, cr, hd, vs;
  vector<i64> ds;
  vector<edge> e;
  inline NetWork(int N) {
    vs.resize(N + 5), n = N, ct = 1;
    dp.resize(N + 5), ds.resize(N + 5);
    cr.resize(N + 5), hd.resize(N + 5);
    e.push_back({}), e.push_back({});
  }
  inline void add(int x, int y, int z, int u) {
    e.push_back({y, hd[x], z, u}), hd[x] = ++ct;
    e.push_back({x, hd[y], 0,-u}), hd[y] = ++ct;
  }
  inline bool bfs() {
    queue<int> q;
    fro(i, 1, n) dp[i] = 0, ds[i] = 1e18, cr[i] = hd[i];
    q.push(s), ds[s] = 0;
    while (q.empty() == 0) {
      int x = q.front(); q.pop(), vs[x] = 0;
      for (int i = hd[x]; i; i = e[i].nxt) {
        if (e[i].v == 0) continue;
        if (ds[e[i].to] > ds[x] + e[i].c) {
          ds[e[i].to] = ds[x] + e[i].c;
          dp[e[i].to] = dp[x] + 1;
          if (!vs[e[i].to]) q.push(e[i].to), vs[e[i].to] = 1;
        }
      }
    }
    return ds[t] != 1e18;
  }
  inline i64 dfs(int now, i64 flow) {
    if (now == t) return mf += flow, flow;
    i64 used = 0;
    for (int&i = cr[now]; i; i = e[i].nxt) {
      if (ds[now] + e[i].c == ds[e[i].to] && dp[now] + 1 == dp[e[i].to] && e[i].v) {
        int x = dfs(e[i].to, min(e[i].v, flow - used));
        e[i].v -= x, e[i ^ 1].v += x, used += x, mc += x * e[i].c;
        if (used == flow) return used;
      }
    }
    return used;
  }
  inline pair<i64, i64> zkw(int S, int T) {
    s = S, t = T, mf = mc = 0;
    while (bfs()) while (dfs(s, 1e18));
    return {mf, mc};
  }
};

signed main() {
  ios::sync_with_stdio(0), cin.tie(0);
  int n, m;
  cin >> n >> m;
  vector<int> h(n + 1);
  NetWork sol(n + 3);
  int s = n + 2, t = n + 3;
  fro(i, 1, n) {
    cin >> h[i];
  }
  fro(i, 1, m) {
    char w; int l, c;
    cin >> w >> l >> c;
    if (w == '+') fro(i, 1 + l, n + 1) sol.add(i, i - l, 1e9, c);
    if (w == '-') fro(i, 1 + 0, n - l) sol.add(i, i + l, 1e9, c);
  }
  sol.add(s, n + 1, 1e9, 0);
  pre(i, n, 1) {
    h[i] = h[i] - h[i - 1];
    if (h[i] > 0) sol.add(s, i, h[i], 0);
    if (h[i] < 0) sol.add(i, t,-h[i], 0);
  }
  auto ans = sol.zkw(s, t);
  fro(i, 2, n) if (h[i] < 0) ans.first += h[i];
  cout << (ans.first == 0 ? ans.second : -1) << "\n";
  return 0;
}
posted @ 2024-06-03 17:46  JiaY19  阅读(2)  评论(0编辑  收藏  举报