P7730 [JDWOI-1] 蜀道难
有 座山,每座山高度为 。
有 种操作,每一次操作可以把连续 座山的高度抬高或压低 ,费用为 。
问,让 座山的高度不下降,最少需多少费用?
如果无解,输出 -1
。
,时限 ,空限 。
std
「蜀道难,难于上青天」。
考虑到,当 座山的高度不下降时,有:,即 。
但是这里修改一个数的话,对它后面的数都有影响,不太好弄。
考虑差分维护,记 ,(这时点之间就互不影响了)。
每次对区间 的操作即 (加) 或 (减)。
那么我们要让 。
考虑到,我们不会让某一座山先抬高再压低或先压低抬高再抬高。
那么对于 ,最多被减 次,即最多为其他点提供 次加;,至少需要被加 次。
总结一下,模型如下:
- 如果 ,连一条从 到 ,容量为 ,费用为 的边(表示这个点有 次给其他点加的机会)。
- 如果 ,连一条从 到 ,容量为 ,费用为 的边(表示这个点需要被加 次)。
- 对于区间 的加法操作,连一条从 到 ,容量为 ,费用为 的边(表示加机会的转移)。
- 对于区间 的减法操作,连一条从 到 ,容量为 ,费用为 的边(表示加机会的转移)。
最后就是跑最小费用最大流了。
记最大流为 ,则无解的情况即为 。
#include <bits/stdc++.h>
using namespace std;
inline int read()
{
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
{
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
inline void write(int x)
{
if (x < 0)
{
putchar('-');
x = -x;
}
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
typedef int tp;
const int _ = 6e5 + 10, inf = 947483647;
int n, m, a[_], b[_], s, t, lv[_], cur[_];
tp maxflow, mincost;
int tot = 1, head[_], to[_ << 1], nxt[_ << 1];
tp dis[_], w[_ << 1], fl[_ << 1];
int mc[2][_];
inline void add(int u, int v, tp dis, tp c)
{
to[++tot] = v;
nxt[tot] = head[u];
fl[tot] = dis;
w[tot] = c;
head[u] = tot;
}
inline void Add(int u, int v, tp dis, tp c)
{
add(u, v, dis, c);
add(v, u, 0, -c);
}
inline bool bfs()
{
memset(lv, 0, sizeof(lv));
for (int i = 0; i < _; ++i)
dis[i] = inf;
lv[s] = 1;
dis[s] = 0;
memcpy(cur, head, sizeof(head));
queue<int> q;
q.push(s);
while (!q.empty())
{
int p = q.front();
q.pop();
lv[p] = 0;
for (int eg = head[p]; eg; eg = nxt[eg])
{
int v = to[eg];
tp vol = fl[eg];
if (vol > 0 && dis[v] > dis[p] + w[eg])
{
dis[v] = dis[p] + w[eg];
if (!lv[v])
{
q.push(v);
lv[v] = 1;
}
}
}
}
return dis[t] != inf;
}
tp dfs(int p = s, tp flow = inf)
{
if (p == t)
return flow;
lv[p] = 1;
tp rmn = flow;
for (int eg = cur[p]; eg && rmn; eg = nxt[eg])
{
cur[p] = eg;
int v = to[eg];
tp vol = fl[eg];
if (vol > 0 && !lv[v] && dis[v] == dis[p] + w[eg])
{
tp c = dfs(v, min(vol, rmn));
rmn -= c;
fl[eg] -= c;
fl[eg ^ 1] += c;
}
}
lv[p] = 0;
return flow - rmn;
}
inline void dinic()
{
while (bfs())
{
tp flow = dfs();
maxflow += flow;
mincost += dis[t] * flow;
}
}
int d1[_], d2[_];
signed main()
{
char op;
int x, y, sum = 0;
n = read(), m = read();
s = 0, t = _ - 1;
for (int i = 1; i <= n; ++i)
{
b[i] = read();
a[i] = b[i] - b[i - 1];
}
for (int i = 0; i <= n + 1; ++i)
d1[i] = d2[i] = inf;
for (int i = 1; i <= m; ++i)
{
cin >> op;
x = read(), y = read();
if (op == '+')
d1[x] = min(d1[x], y);
else
d2[x] = min(d2[x], y);
}
Add(s, n + 1, inf, 0);
for (int i = 1; i <= n; ++i)
if (a[i] > 0)
Add(s, i, a[i], 0);
else
{
Add(i, t, -a[i], 0);
sum -= a[i];
}
for (int i = 1; i <= n; ++i)
for (int l = 1, r = l + i; r <= n + 1; ++l, r = l + i)
{
if (d1[i] < inf)
Add(r, l, inf, d1[i]);
if (d2[i] < inf)
Add(l, r, inf, d2[i]);
}
dinic();
if(maxflow < sum)
{
puts("-1");
return 0;
}
write(mincost), putchar('\n');
return 0;
}
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18122029