CF2097F Lost Luggage 题解

Description

众所周知,航空公司"Trouble"经常丢失行李,为此关心的记者们决定计算可能无法归还给旅客的行李最大数量。

航空公司"Trouble"在编号从 11nnnn 个机场间运营航班。记者们的实验将持续 mm 天。已知在实验第一天午夜前,第 jj 个机场有 sjs_j 件遗失行李。在第 ii 天会发生以下事件:

  • 早晨,同时起飞 2n2n 个航班,包括 nn 个第一类航班和 nn 个第二类航班:
    • 第一类第 jj 个航班从机场 jj 飞往机场 (((j2)modn)+1)(((j-2) \bmod n )+ 1)(前一个机场,第一个机场的前一个是最后一个),最多可运输 ai,ja_{i,j} 件遗失行李;
    • 第二类第 jj 个航班从机场 jj 飞往机场 ((jmodn)+1)((j \bmod n) + 1)(后一个机场,最后一个机场的后一个是第一个),最多可运输 ci,jc_{i,j} 件遗失行李;
  • 下午,机场会进行遗失行李检查。如果当天航班起飞后,第 jj 个机场剩余 xx 件行李且 xbi,jx \ge b_{i, j},则至少会有 xbi,jx - b_{i, j} 件行李被找到,不再视为遗失;
  • 晚上,当天所有 2n2n 个航班结束,运输的遗失行李抵达对应机场。

对于每个 kk11mm,记者们想知道在前 kk 天的检查中可能未被找到的遗失行李最大数量。注意每个 kk 的计算都是独立的。

1n12,1m20001\leq n\leq 12,1\leq m\leq 2000

Solution

首先这个显然是网络流,有一个比较显然的最大流建模是建给第 i(0im)i(0\leq i\leq m) 天建一个点 (i,j)(i,j) 表示这一天晚上机场 jj 的行李数量,同时第 ii 天有个汇点 TiT_i。连边就是 (i1,j)(i-1,j)(i,j)(i,j) 连流量为 bi,jb_{i,j} 的边,(i1,j)(i-1,j)(i,j1)(i,j-1) 连流量为 ai,ja_{i,j} 的边,(i1,j)(i-1,j)(i,j+1)(i,j+1) 连流量为 ci,jc_{i,j} 的边,(i,j)(i,j)TiT_i 连流量为 ++\infty 的边。第 ii 天的答案就是 STiS\to T_i 的最大流。

但是直接跑肯定是不行的。考虑转最小割。

由于 n12n\leq 12 且只有相邻层数之间的边,所以可以直接按照天数把和 SS 连通的点压入状态。

fi,Sf_{i,S} 表示前 ii 天,钦定第 ii 层和源点相连的点为集合 SS 内的点,其余的全和汇点相连。

转移为:

fi,S=minT{fi1,S+jTkSei1,j,k}f_{i,S}=\min_{T}{\left\{f_{i-1,S}+\sum_{j\in T}\sum_{k\notin S}{e_{i-1,j,k}}\right\}}

注意:这里转移的边必须满足前面的点属于 TT,后面的不属于 SS,不能加入前面属于 SS 后面不属于 TT 的贡献,因为这样的边根本不会被经过!!!

直接转移是 O(m4n)O(m\cdot 4^n),过不了。优化就考虑先把初始状态设为上一层的状态,然后从前往后逐位修改状态,设 gi,S,0/1g_{i,S,0/1} 表示修改了前 ii 位,目前状态为 SS,且第 ii 位在修改前是 0/10/1 的最小答案。容易转移。

单次转移是 O(2nn)O(2^nn)

时间复杂度:O(nm2n)O(nm\cdot 2^n)

Code

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <bits/stdc++.h>

#define int int64_t

const int kMaxN = 15, kMaxM = 2e3 + 5, kMaxS = (1 << 13) + 5;

int n, m;
int cnt[kMaxN], a[kMaxM][kMaxN], b[kMaxM][kMaxN], c[kMaxM][kMaxN];
int f[kMaxS];

inline void chkmax(int &x, int y) { x = (x > y ? x : y); }
inline void chkmin(int &x, int y) { x = (x < y ? x : y); }

void dickdreamer() {
std::cin >> n >> m;
for (int i = 1; i <= n; ++i) std::cin >> cnt[i];
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) std::cin >> a[i][j];
for (int j = 1; j <= n; ++j) std::cin >> b[i][j];
for (int j = 1; j <= n; ++j) std::cin >> c[i][j];
}
for (int s = 0; s < (1 << n); ++s) {
f[s] = 0;
for (int i = 1; i <= n; ++i)
if (s >> (i - 1) & 1)
f[s] += cnt[i];
}
for (int i = 1; i <= m; ++i) {
static int g[kMaxS][2], tmp[kMaxS][2];
for (int s = 0; s < (1 << (n + 1)); ++s) g[s][0] = g[s][1] = 1e18;
for (int s = 0; s < (1 << n); ++s) g[s | ((s & 1) << n)][s >> (n - 1) & 1] = f[s];
for (int j = 0; j < n; ++j) {
for (int s = 0; s < (1 << (n + 1)); ++s)
for (int o = 0; o < 2; ++o)
tmp[s][o] = g[s][o], g[s][o] = 1e18;
for (int s = 0; s < (1 << (n + 1)); ++s) {
for (int o1 = 0; o1 < 2; ++o1) {
for (int o2 = 0; o2 < 2; ++o2) {
int val = tmp[s][o1], t = s;
if (o2 ^ (s >> j & 1)) t ^= (1 << j);
val += ((o1 == 0) && (o2 == 1)) * c[i][(j + n - 1) % n + 1];
val += (((s >> j & 1) == 0) && (o2 == 1)) * b[i][j + 1];
val += (((s >> (j + 1) & 1) == 0) && (o2 == 1)) * a[i][(j + 1) % n + 1];
chkmin(g[t][s >> j & 1], val);
}
}
}
}
std::fill_n(f, 1 << n, 1e18);
for (int s = 0; s < (1 << (n + 1)); ++s) chkmin(f[s & ((1 << n) - 1)], std::min(g[s][0], g[s][1]));
std::cout << f[(1 << n) - 1] << '\n';
}
}

int32_t main() {
#ifdef ORZXKR
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
int T = 1;
std::cin >> T;
while (T--) dickdreamer();
// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
return 0;
}

CF2097F Lost Luggage 题解
https://sobaliuziao.github.io/2025/07/28/post/37bd1483.html
作者
Egg_laying_master
发布于
2025年7月28日
许可协议