题目链接
这个题想了半天.最后构建这样一个模型:
对于N天
1.对每一天
i
i
i,拆点,拆成两个
(
i
,
i
+
N
)
(i,i+N)
(i,i+N).中间连一条容量为当天需要餐巾数量,费油为0的边
<
i
,
i
+
N
,
a
[
i
]
,
0
>
<i,i+N,a[i],0>
<i,i+N,a[i],0>.
2.对于每天的后点,都往下一天连一条容量为inf,费用为0的边
<
i
+
N
,
i
+
N
+
1
,
i
n
f
,
0
>
<i+N,i+N+1, inf, 0>
<i+N,i+N+1,inf,0>
3.对于每一个后点,都往n和m天后的前点连一条容量为inf,费用为s或f的边
<
i
+
N
,
i
+
m
,
i
n
f
,
f
>
<i+N, i+m, inf,f>
<i+N,i+m,inf,f>和
<
i
+
N
,
i
+
n
,
i
n
f
,
s
>
<i+N,i+n,inf,s>
<i+N,i+n,inf,s>
4.对于每一个前点,都往超级源点连一条边
<
s
,
i
,
i
n
f
,
p
>
<s,i,inf,p>
<s,i,inf,p>
这时显然,我们必须监控:让1中所连的边跑到满流的情况下,得出最小费…想了很久,最后得出一个监控一批边满流的实际方法:
对于想监控的那批边
<
x
,
y
,
f
,
c
>
<x,y,f,c>
<x,y,f,c>:
1.删除原边.
2.对于每一个边我们向汇点连一条
<
x
,
t
,
f
,
c
>
<x,t,f,c>
<x,t,f,c>
3.对于每一条边我们从源点连一条
<
s
,
y
,
f
,
0
>
<s,y,f,0>
<s,y,f,0>
然后从源点向汇点跑一个费用流,就可以得出在特定一批边满流后的最小费用了.
…上述理论系本人自己琢磨出来,缺乏证明,缺乏证明,缺乏证明,正确性未知,但洛谷题已过…
下面是ac代码:
#include <iostream>
#include <string>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
#include <set>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#define ll long long
#define int ll
#define max(x, y) ((x)>(y)?(x):(y))
#define min(x, y) ((x)<(y)?(x):(y))
#define pr(x, y) make_pair((x), (y))
using namespace std;
const int N = 2e6+5;
const int M = 2e6+5;
const int inf = 0x3f3f3f3f;
int tot;
int mx, h[N], dis[N], pre[N];
int he[N], ne[M], ver[M], e[M], c[M];
void init(int n)
{
mx = n;
tot = 1;
}
void add(int x, int y, int w, int _c)
{
// cout << x << "->" << y << "::" << w << " " << _c << endl;
ver[++tot] = y;
ne[tot] = he[x];
he[x] = tot;
c[tot] = _c;
e[tot] = w;
ver[++tot] = x;
ne[tot] = he[y];
he[y] = tot;
e[tot] = 0;
c[tot] = -_c;
}
int EK(int s, int t, int f, int &flow)
{
int res = 0;
fill(h, h + 1 + mx, 0);
while(f)
{
priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > q;
fill(dis, dis + 1 + mx, inf);
dis[s] = 0; q.push(pr(0, s));
while(q.size())
{
pair<int, int> now = q.top(); q.pop();
int te = now.second;
if (dis[te] < now.first) continue;
for (int i = he[te]; i; i = ne[i])
{
if (e[i] > 0 && dis[ver[i]] > dis[te] + c[i] + h[te] - h[ver[i]])
{
dis[ver[i]] = dis[te] + c[i] + h[te] - h[ver[i]];
pre[ver[i]] = i;
q.push(pr(dis[ver[i]], ver[i]));
}
}
}
if (dis[t] == inf) break;
for (int i = 0; i <= mx; i++) h[i] += dis[i];
int d = f;
for (int i = pre[t]; i; i = pre[ver[i^1]]) d = min(d, e[i]);
f -= d; flow += d; res += d * h[t];
for (int i = pre[t]; i; i = pre[ver[i^1]])
{e[i] -= d; e[i^1] += d;}
}
return res;
}
int su[N];
signed main()
{
int n;
cin >> n;
int s = 0, t = (n << 1) + 1;
init(t);
for (int i = 1; i <= n; i++)
scanf("%lld", &su[i]);
int p, m, f, _n, _s;
scanf("%lld%lld%lld%lld%lld", &p, &m, &f, &_n, &_s);
for (int i = 1; i <= n; i++)
{
if (i != n) add(i + n, i + n + 1, inf, 0);
add(s, i, inf, p);
add(s, i + n, su[i], 0);
add(i, t, su[i], 0);
if (i + m <= n) add(i + n, i + m, inf, f);
if (i + _n <= n) add(i + n, i + _n, inf, _s);
}
int flow = 0;
int ans = EK(s, t, inf, flow);
printf("%lld\n", ans);
return 0;
}