
题目链接:
http://codeforces.com/contest/1139/problem/E
题意:
开始有$n$个同学和$m$,每个同学有一个天赋$p_{i}$和一个俱乐部$c_{i}$,然后在$d$天里,每天早上去除一名同学$k_{i}$,每天中午在每个俱乐部选一个人组成战队。战队的战斗力是最小的不存在的天赋,例如{1,2,3,0}战斗力是4,问每天战队的战斗力最大为多少。
数据范围:
$1 \leq m \leq n \leq 5000$
$0 \leq p_i < 5000$
$1 \leq c_i \leq m$
$1 \leq d \leq n$
$1 \leq k_i \leq n$
分析:
每次减边,然后对整体二分图匹配复杂度大概是$O\left ( n^{3} \right )$
于是想到逆序处理,从后往前处理,逆过程就是加边,由于加边后的ans肯定是递增的,所以复杂度降成$O\left ( n^{2} \right )$
如果用邻接矩阵复杂度是$O\left ( n^{3} \right )$用邻接表是$O\left ( n^{2} \right )$,因为对于二分图这道题的边数为$n$,属于稀疏图,所以用邻接表比较合适
ac代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e3+;;
int match[maxn],vis[maxn],ans[maxn],p[maxn],c[maxn],k[maxn],d,n,m;
int ma[maxn][maxn],book[maxn],f[maxn],to[maxn],cnt,nex[maxn];
void add(int a,int b)
{
cnt++;
to[cnt]=b;
nex[cnt]=f[a];
f[a]=cnt;
}
bool dfs(int x)
{
if(vis[x])return false;
vis[x]=;
for(int i=f[x]; i; i=nex[i])
{
int v=to[i];
if(match[v]==-||dfs(match[v]))
{
match[v]=x;
return true;
}
}
return false;
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=; i<maxn; i++)match[i]=-;
for(int i=; i<=n; i++)
scanf("%d",&p[i]);
for(int i=; i<=n; i++)
scanf("%d",&c[i]);
scanf("%d",&d);
for(int i=; i<=d; i++)
{
scanf("%d",&k[i]);
book[k[i]]=;
}
for(int i=; i<=n; i++)
if(book[i]==)add(p[i],c[i]); for(int i=d; i>=; i--)
{
ans[i]=ans[i+];
while()
{
memset(vis,,sizeof(vis));
if(dfs(ans[i]))ans[i]++;
else break;
}
int x=k[i];
add(p[x],c[x]);
}
for(int i=; i<=d; i++)
printf("%d\n",ans[i]);
return ;
}