题解 CF802N 【April Fools' Problem (medium)】
题意简述
给定两个序列,\(\{a_i\}\) 和 \(\{b_i\}\)。要求选出 \(\{i_k\}\) 和 \(\{j_k\}\),满足:
- \(i_l\le i_m(1\le l\le m\le k)\),\(j_l\le j_m(1\le l\le m\le k)\);
- \(i_p\le j_p(1\le p\le k)\);
求 \(\min\left(\displaystyle\sum_{p=1}^k (a_{i_p}+b_{j_p})\right)\)。
思路简述
我们先看一眼数据范围——\(n\le 2200\),这暗示我们时间复杂度应该会劣于\(O(n^2)\)。
我们考虑一个图,满足:
- 有 \(n+2\) 个节点,其中第 \(i\) 天 \(1\) 个节点,编号为 \(i\)(\(i=1,2,3,\cdots,n\)),有一个起点(源)\(s\),一个终点(宿)\(t\)。
- 对于每一天(记当天为第 \(i\) 天,\(i=1,2,3,\cdots,n\)),加 \(3\) 条边:
- 从 \(s\) 到 \(i\),流量为 \(1\),费用为 \(a_i\)。
- 从 \(i\) 到 \(i+1\),第 \(n\) 天无此边,流量为 \(k\),费用为 \(0\)。
- 从 \(i\) 到 \(t\),流量为 \(1\),费用为 \(b_i\)。
不难看出,在该图中,当流量为 \(k\) 时,最小费用刚好为我们所求的 \(\min\left(\displaystyle\sum_{p=1}^k (a_{i_p}+b_{j_p})\right)\)。随便分析一下时间复杂度,为 \(O(nm)\),足以通过此题。
核心代码如下(用到了 AtCoder 的模板库):
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
cin >> n >> k;
mcf_graph<ll, ll> graph(n + 2);
for (int i = 1; i <= n; i++) {
int temp;
cin >> temp;
graph.add_edge(0, i, 1, temp);
if (i < n) graph.add_edge(i, i + 1, k, 0);
}
for (int i = 1; i <= n; i++) {
int temp;
cin >> temp;
graph.add_edge(i, n + 1, 1, temp);
}
pair<long long, long long> ans = graph.flow(0, n + 1, k);
cout << ans.second << endl;
return 0;
}

浙公网安备 33010602011771号