题意
有 n个人,每个人有一个属性值 ci,并属于唯一的一个俱乐部 bi,有 d天,每天指定一个人离开他所属的俱乐部(以后不再回来),离开后,每一个俱乐部每天要推举一个人,每天被推举上来的人的属性值构成序列 S,要使 S的 mex值最大,输出每天的 mex最大值。
mex是指在一个序列中没有出现的最小自然数,在博弈论的SG函数中用到。
例如: [0,1,2,4]的 mex值为 3, [1,2,3]的 mex值为 0。
题解
这是一个匹配问题。相当于每一个俱乐部匹配一个属性值,亦或是每一个属性值匹配一个俱乐部,要使 mex最大,匹配数一定是越来越多的。因为 mex本身的性质,我们要从 0开始,给每一个属性值匹配一个俱乐部,如果匹配到某个属性值 x时,无法匹配到俱乐部时, mex就得到了。
建好‘属性值-俱乐部’的图之后,用KM算法匹配即可。
由于每天都有人离开,所以图是不一样的,暴力求解会超时。发现随着人越走越多,答案会越来越小。逆向考虑,时间从后往前,人越来越多。新的图的 mex值一定是大于等于旧图的 mex值的,所以,这样就可以利用之前匹配的结果,在此基础上,看能否增加匹配即可。
代码
#include<bits/stdc++.h>
#define N 50010
#define INF 0x3f3f3f3f
#define eps 1e-10
#define pi 3.141592653589793
#define P 1000000007
#define LL long long
#define pb push_back
#define cl clear
#define si size
#define lb lower_bound
#define ub upper_bound
#define mem(x) memset(x,0,sizeof x)
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
vector<int> a[N];
int f[N],c[N],b[N],d[N],ans[N],match[N],cnt;
bool dfs(int x)
{
f[x]=cnt;
for (auto i:a[x])
{
if (match[i]!=-1 & f[match[i]]==cnt) continue;
if (match[i]==-1 || dfs(match[i]))
{
match[i]=x;
return 1;
}
}
return 0;
}
int main()
{
int n,m;
scc(n,m);
for (int i=1;i<=n;i++) sc(c[i]);
for (int i=1;i<=n;i++) sc(b[i]);
int q;
sc(q);
for (int i=1;i<=q;i++) sc(d[i]),f[d[i]]=1;
for (int i=1;i<=n;i++) if (!f[i])
a[c[i]].pb(b[i]);
memset(match,-1,sizeof match);
cnt=1;
for (int i=q;i;i--)
{
cnt++;
ans[i]=ans[i+1];
while(dfs(ans[i])) {ans[i]++;cnt++;}
a[c[d[i]]].pb(b[d[i]]);
}
for (int i=1;i<=q;i++)printf("%d\n",ans[i]);
}