BZOJ传送门
洛谷传送门
解析:
显然你需要在自己脑子里补一个条件,不然就写一个tarjan求SCC。。。
这个图应该是DAG,如果不是,讨论会有点麻烦。
然后二分答案,看一下将答案以下的点全部覆盖至少需要多少条链就行了。
。。。
来吐槽几点。
首先,没有明说是DAG,其次没有明说一道题可以重复回答(这是最小链覆盖的基础要求,不然就是最小路径覆盖了)
难道TJOI没有验题人吗?
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define cs const
cs int N=505;
bool g[N][N];
int k,m,len;
int val[N];
inline void Floyd(){
for(int re i=1;i<=m;++i){
for(int re j=1;j<=m;++j){
if(i^j)
for(int re k=1;k<=m;++k){
g[j][k]|=g[j][i]&&g[i][k];
}
}
}
}
bool ban[N];
int match[N],vis[N];
int idx;
inline bool find(int u){
if(ban[u])return false;
for(int re v=1;v<=m;++v){
if(!ban[v]&&g[u][v]&&(vis[v]^idx)){
vis[v]=idx;
if(!match[v]||find(match[v])){
match[v]=u;
return true;
}
}
}
return false;
}
inline bool check(int lim){
for(int re i=1;i<=m;++i)ban[i]=val[i]>=lim;
memset(match,0,sizeof match);
++idx;
for(int re i=1;i<=m;++i,++idx)find(i);
int cnt=0;
for(int re i=1;i<=m;++i)if(!ban[i]&&!match[i])++cnt;
return cnt<=k+1;
}
int b[N];
signed main(){
scanf("%d%d",&k,&m);
for(int re i=1,tmp,x;i<=m;++i){
scanf("%d%d",&val[i],&tmp);
b[i]=val[i];
while(tmp--){
scanf("%d",&x);
g[i][x]=true;
}
}
Floyd();
sort(b+1,b+m+1);
len=unique(b+1,b+m+1)-b-1;
if(check(b[len]+1))puts("AK"),exit(0);
int l=1,r=len;
while(l<r){
int mid=(l+r+1)>>1;
if(check(val[mid]))l=mid;
else r=mid-1;
}
cout<<val[l]<<"\n";
return 0;
}