题面
解法
当年我果然还是太菜了
- 先考虑第一问怎么解决
- 对于每一个选手 i i i,连接 ( S , i , 1 ) (S,i,1) (S,i,1);对于每一个评委 j j j,连接 ( j , T , b [ j ] ) (j,T,b[j]) (j,T,b[j])。
- 选手按照编号从小到大处理,枚举最后的答案,然后加上相应的边,看是否能够增广就可以了。
- 对于第二问,可以记录一下每一个选手做完之后的残量网络,二分答案即可。
【注意事项】
- 建议在第一问枚举答案的时候删去不需要的边,即发现 j j j不能作为答案时将第 j j j志愿相关的边全部删去,可以加快一点速度。
代码
#include <bits/stdc++.h>
using namespace std;
template <typename T> void chkmax(T &x, T y) {x = x > y ? x : y;}
template <typename T> void chkmin(T &x, T y) {x = x > y ? y : x;}
template <typename T> void read(T &x) {
x = 0; int f = 1; char c = getchar();
while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
const int N = 410, inf = 1 << 30;
int n, m, s, t, cnt, l[N], b[N], ed[N], tx[N], fr[N], cur[N], lev[N], head[N], h[N][N];
vector <int> v[N][N];
struct Edge {int pre, from, next, num, c;} e[N * N], E[210][10010];
void add(int x, int y, int c) {
e[++cnt] = (Edge) {0, x, head[x], y, c};
e[e[cnt].next].pre = head[x] = cnt;
}
void del(int p) {
int x = e[p].from;
if (p != head[x]) {
e[e[p].pre].next = e[p].next;
if (e[p].next) e[e[p].next].pre = e[p].pre;
} else head[x] = e[p].next;
}
void Add(int x, int y, int c) {add(x, y, c), add(y, x, 0);}
bool bfs(int s, int t) {
memset(l, -1, sizeof(l));
queue <int> q; q.push(s), l[s] = 0;
while (!q.empty()) {
int x = q.front(); q.pop();
for (int p = head[x]; p; p = e[p].next) {
int k = e[p].num, c = e[p].c;
if (l[k] == -1 && c) l[k] = l[x] + 1, q.push(k);
}
}
return l[t] != -1;
}
int dfs(int x, int t, int lim) {
if (x == t) return lim; int ret = 0;
for (int &p = cur[x]; p; p = e[p].next) {
int k = e[p].num, c = e[p].c;
if (l[k] == l[x] + 1 && c) {
int w = dfs(k, t, min(lim - ret, c));
e[p].c -= w, e[p ^ 1].c += w, ret += w;
if (ret == lim) return ret;
}
}
if (!ret) l[x] = -1; return ret;
}
int dinic(int s, int t) {
int ret = 0;
while (bfs(s, t)) {
memcpy(cur, head, sizeof(cur));
ret += dfs(s, t, inf);
}
return ret;
}
bool check(int id, int rnk, int lev) {
for (int i = s; i <= t; i++) head[i] = h[rnk - 1][i];
for (int i = 2; i <= ed[rnk - 1]; i++) e[i] = E[rnk - 1][i];
for (int i = 1; i <= lev; i++)
for (int j = 0; j < v[id][i].size(); j++) Add(id, v[id][i][j] + n, 1);
return dinic(s, t);
}
int main() {
int T, c; read(T), read(c);
while (T--) {
read(n), read(m); cnt = 1;
memset(e, 0, sizeof(e)), memset(head, 0, sizeof(head));
for (int i = 1; i <= m; i++) read(b[i]);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
v[i][j].clear();
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
int x; read(x);
v[i][x].push_back(j);
}
for (int i = 1; i <= n; i++) read(tx[i]), lev[i] = m + 1;
s = 0, t = n + m + 1;
for (int i = 1; i <= n; i++) Add(s, i, 1), fr[i] = cnt;
for (int i = 1; i <= m; i++) Add(i + n, t, b[i]);
for (int i = s; i <= t; i++) h[0][i] = head[i];
for (int i = 1; i <= cnt; i++) E[0][i] = e[i];
int las = cnt; ed[0] = cnt;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
for (int k = 0; k < v[i][j].size(); k++) Add(i, v[i][j][k] + n, 1);
int tmp = dinic(s, t);
if (e[fr[i]].c) {lev[i] = j, las = cnt; break;}
for (int k = las + 1; k <= cnt; k++) del(k); cnt = las;
}
ed[i] = cnt;
for (int j = 1; j <= cnt; j++) E[i][j] = e[j];
for (int j = s; j <= t; j++) h[i][j] = head[j];
}
for (int i = 1; i <= n; i++) cout << lev[i] << ' '; cout << "\n";
for (int i = 1; i <= n; i++) {
if (lev[i] <= tx[i]) {cout << "0 "; continue;}
int l = 1, r = i - 1, ans = i;
while (l <= r) {
int mid = (l + r) >> 1;
if (check(i, i - mid, tx[i])) ans = mid, r = mid - 1;
else l = mid + 1;
}
cout << ans << ' ';
}
cout << "\n";
}
return 0;
}