网络流杂题
Increase to make it Increasing
首先差分,这是毋庸置疑的。
然后问题就转化成每次操作可以给 \(L_i\) 位置 \(+1\),给 \(R_i+1\) 位置 \(-1\),最后要求 \(1\sim n\) 每个位置都是 \(\ge 0\) 的。
这个感觉可以 dp 或者贪心?
应该是一个贪心,因为只需要满足每个位置 \(\ge 0\),所以对于一个 \(\lt 0\) 的位置,考虑对它操作。
好像是可以转化到网络流模型的,就源点向每个 \(d_i\ge 0\) 的 \(i\) 连边,流量是 \(d_i\)(这里表示差分数组),然后每个 \(d_i\lt 0\) 的 \(i\) 向汇点连边,流量是 \(|d_i|\)。
特殊的,\(d_{n+1}\) 为 \(inf\)。
然后每个操作的 \(R_i+1\) 向 \(L_i\) 连边,流量 \(inf\),费用为 \(1\)。
然后跑就行了。
代码
#include <bits/stdc++.h>
void Freopen() {
freopen("", "r", stdin);
freopen("", "w", stdout);
}
using namespace std;
const int N = 2e5 + 10, M = 2e5 + 10, inf = 1e9, mod = 998244353;
int n, m, sum;
int a[N], d[N];
int cnt = 1, S, T;
int dis[N], vis[N], dep[N], head[N];
struct edge {
int to, nxt, w, c;
} E[N];
void add( int x, int y, int z, int p) {
E[++ cnt] = {y, head[x], z, p}, head[x] = cnt;
E[++ cnt] = {x, head[y], 0, -p}, head[y] = cnt;
}
bool spfa() {
for ( int i = 0; i <= T; i ++) dis[i] = inf, vis[i] = 0;
queue< int> q;
q.push(S), dis[S] = 0, vis[S] = 1;
while (q.size()) {
int u = q.front();
q.pop(), vis[u] = 0;
for ( int i = head[u], v; i; i = E[i].nxt)
if (E[i].w && dis[v = E[i].to] > dis[u] + E[i].c) {
dis[v] = dis[u] + E[i].c, dep[v] = dep[u] + 1;
if (! vis[v]) vis[v] = 1, q.push(v);
}
}
return dis[T] != inf;
}
int dfs( int u, int f, int & mco) {
if (u == T) return f;
int res = f;
for ( int i = head[u], v; i; i = E[i].nxt)
if (E[i].w && dep[v = E[i].to] == dep[u] + 1)
if (dis[v] == dis[u] + E[i].c) {
int now = dfs(v, min(E[i].w, res), mco);
if (! now) dep[v] = 1;
else {
res -= now, mco += E[i].c * now;
E[i].w -= now, E[i ^ 1].w += now;
}
if (! res) return f;
}
return f - res;
}
pair< int, int> dinic() {
int mxl = 0, mnc = 0;
while (spfa()) mxl += dfs(S, inf, mnc);
return {mxl, mnc};
}
signed main() {
ios :: sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> m;
for ( int i = 1; i <= n; i ++) cin >> a[i];
a[n + 1] = inf;
for ( int i = 1; i <= n + 1; i ++) d[i] = a[i] - a[i - 1];
S = n + 2, T = n + 3;
for ( int i = 1; i <= n + 1; i ++) {
if (d[i] >= 0) add(S, i, d[i], 0);
else add(i, T, abs(d[i]), 0), sum += abs(d[i]);
}
while (m --) {
int l, r; cin >> l >> r;
add(r + 1, l, inf, 1);
}
auto res = dinic();
if (res.first != sum) cout << "-1\n";
else cout << res.second << '\n';
return 0;
}