ARC137E 题解

First Post:

Last Update:

对与区间有关的建模不够熟悉,即使想到了根据面包师建模,也难以建出东西来。

需要对这方面加以训练。

题意:

天, 个面包师,第 个面包师需要花 元雇佣,雇佣过后,他会在第 到第 天,每天给你生产一个面包。

每天有个预期销售量 ,如果你当天产出了 个面包,你实际只能卖出 个面包。

卖出一个面包可以获得 元的收益。现在你是面包铺老板,请最大化自己的收益。

对面包建模是比较寄的。

那不妨根据面包师建模。

先把答案取反,变成最小费用模型。

尝试建边 代表每一天的情况,因为这一天卖 个面包,每个可以带来 的贡献,溢出的则没贡献,所以建边

对于一个面包师,建边 ,那么这就是一个循环流模型。我们每次增广一个圈,就相当于选择了一个面包师。

注意到边有负权,我们使用带负权的最小费用流 即可完成计算。

因为这张图非常特殊,每个点连向 与连向 的边的数量是相等的,所以我们甚至不需要虚拟源汇,直接以 为源点, 为汇点跑就可以了。

所以我们总共只需要建出三类边:

注意: 本题在新图中需要保证流量不超过 ,因为在新图中有可能增广出大于 的流量,但这些东西是对应不回原来的流量意义的。

因为这题 稍大,需要 的原始对偶算法方可通过(我写了但被卡常乐),所以我最终使用的是 AtCoder Library 自带的费用流,跑得很快。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <bits/stdc++.h>
#include <atcoder/mincostflow>
#pragma GCC optimize(3)
using namespace std;
typedef long long ll;
const ll llinf = 0x3f3f3f3f3f3f3f3f;
int n,m,D;
ll ans;
int main()
{
cin >> n >> m >> D;
atcoder::mcf_graph<ll,ll> G(n+2);

for(int i = 1;i <= n;i++)
{
int a;
cin >> a;
G.add_edge(i,i + 1,a,D);
G.add_edge(i,i + 1,m - a,0);
ans += 1ll * D * a;
}
for(int i = 1;i <= m;i++)
{
int l,r,c;
cin >> l >> r >> c;
G.add_edge(l,r + 1,1,c);
}
cout << ans - G.flow(1,n + 1,m).second << endl;
return 0;
}