2021牛客暑期多校训练营3 C. Minimum grid

链接

https://ac.nowcoder.com/acm/contest/11254/C

题意

$n*n$ 的网格中,给出每行每列的最大权值,有 $m$ 个位置可以分配权值,求这 $m$ 个位置满足每行每列的最大权值的最小权值和。

思路

行列最大权值的上限为 $1e6$,考虑从大到小枚举权值,记当前枚举到 $x$:

对于最大权值为 $x$ 的行列建立二分图,易发现填 $x$ 的格子数为当前二分图点数 $-$ 最大匹配数。

代码

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
#include <bits/stdc++.h>
#define SZ(x) (int)(x).size()
#define ALL(x) (x).begin(),(x).end()
#define PB push_back
#define EB emplace_back
#define MP make_pair
#define FI first
#define SE second
using namespace std;
typedef double DB;
typedef long double LD;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
typedef vector<int> VI;
typedef vector<PII> VPII;
// head
const int N=1e6+5;
VI mx1[N],mx2[N],a,b;
int match[505];
bool w[2005][2005],st[505];
bool dfs(int u) {
for(int v=0;v<SZ(b);v++) if(w[a[u]][b[v]]&&!st[v]) {
st[v]=true;
if(match[v]==-1||dfs(match[v])) {
match[v]=u;
return true;
}
}
return false;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n,m,k;cin>>n>>m>>k;
for(int i=1;i<=n;i++) {
int x;cin>>x;
mx1[x].PB(i);
}
for(int i=1;i<=n;i++) {
int x;cin>>x;
mx2[x].PB(i);
}
for(int i=1;i<=m;i++) {
int x,y;cin>>x>>y;
w[x][y]=true;
}
int res=0;
for(int i=k;i;i--) {
a.clear();
b.clear();
for(auto x:mx1[i]) a.PB(x);
for(auto x:mx2[i]) b.PB(x);
for(int i=0;i<SZ(b);i++) match[i]=-1;
int cnt=SZ(a)+SZ(b);
for(int i=0;i<SZ(a);i++) {
for(int j=0;j<SZ(b);j++) st[j]=false;
if(dfs(i)) --cnt;
}
res+=cnt*i;
}
cout<<res<<'\n';
return 0;
}