题意:n(5000)个学生,m个社团(5000),每个学生有一个值ai和归属的社团bi,现在领导想让不同社团出一个人,使得出来的人的值可以从0连续排到ans。每天有一个学生会退出自己的社团,问当天的最大ans是多少。
思路:
- 如果倒着来的话,那么就成别人进社团了,这样想好像问题简单一些。
- 我们把学生的值作为二分图的一个集合,社团作为二分图的一个集合,这样当天的最大值就成了二分图最大匹配问题。
- 既然我们倒着来,那么ans是可以dp推上去的,既上一次的ans为新一次的ans最小答案,这样复杂度的问题就解决了。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int maxn = 5005;
int head[maxn],a[maxn],b[maxn],del[maxn],mat[maxn],tot;
bool vis[maxn],viss[maxn];
struct edge{
int v,nex;
}e[maxn];
void add(int u,int v){
e[++tot] = {v,head[u]},head[u] = tot;
}
bool find(int u){
for(int i =head[u];i;i = e[i].nex){
int v = e[i].v;
if(vis[v]) continue;
vis[v] = 1;
if(!mat[v]||find(mat[v])){
mat[v] = u;
return 1;
}
}
return 0;
}
int main(){
IO;
int n,m;cin>>n>>m;
for1(i,n){
cin>>a[i];
a[i]++;
}
for1(i,n) cin>>b[i];
int k;cin>>k;
for1(i,k){
cin>>del[i];
//cerr<<"@!#!@# "<<del[i]<<'
';
viss[del[i]] = 1;
}
for1(i,n)if(!viss[i]){
add(a[i],b[i]);
}
int ans = 1;stack<int>s;
for(int i = k;i>=1;i--){
for(;ans<=5001;ans++){
memset(vis,0,sizeof(vis));
if(!find(ans)) break;
}
s.push(ans-1);
//cerr<<"!@#!@#@!# "<<del[i]<<' '<<vis[del[i]]<<'
';
if(viss[del[i]]){
//cerr<<a[del[i]]<<' '<<b[del[i]]<<'
';
viss[del[i]] = 0;
add(a[del[i]],b[del[i]]);
}
}
//cout<<'
';
while(!s.empty()){
cout<<s.top()<<'
';
s.pop();
}
return 0;
}