题意不太明确......
这题的n需要一上来就+1。就是求一个可交最小路径覆盖,二分答案即可。
不知道为什么我的常数那么大,别人几乎300ms就完事了,我需要800ms。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
inline char gc() {
static char now[1<<16], *S, *T;
if(S == T) {T = (S = now) + fread(now, 1, 1<<16, stdin); if(S == T) return EOF;}
return *S++;
}
inline int read() {
int x = 0; char c = gc();
while(c < '0' || c > '9') c = gc();
while(c >= '0' && c <= '9') {x = x * 10 + c - 48; c = gc();}
return x;
}
inline void print(int x) {
if(!x) {puts("0"); return ;}
int dgt[20], now = 0;
while(x) {dgt[++now] = x % 10; x/= 10;}
for(; now; --now) putchar('0' + dgt[now]); puts("");
}
int n, m, f[510][510], v[510], b[510]; bool can[510];
int match[510], vis[510];
bool dfs(int x) {
for(int i = 1; i <= m; ++i) {
if(can[i] && f[x][i] && !vis[i]) {
vis[i] = 1;
if(!match[i] || dfs(match[i])) {match[i] = x; return true;}
}
}
return false;
}
inline int check(int tot) {
int res = 0; memset(match, 0, sizeof(match));
for(int i = 1; i <= m; ++i) {
memset(vis, 0, sizeof(vis));
if(can[i] && dfs(i)) ++res;
if(tot - res <= n + 1) return tot - res;
}
return tot - res;
}
int main() {
n = read(); m = read();
for(int i = 1; i <= m; ++i) {
v[i] = read(); int num = read(); can[i] = 1;
for(int j = 1; j <= num; ++j) f[i][read()] = 1;
}
for(int k = 1; k <= m; ++k)
for(int i = 1; i <= m; ++i)
for(int j = 1; j <= m; ++j) f[i][j]|= f[i][k] & f[k][j];
memcpy(b, v, sizeof(b)); sort(b+1, b+m+1); b[m + 1] = 1e9 + 1;
int l = 1, r = m + 1, ans = 0;
while(l <= r) {
int mid = (l + r)>>1; mid = b[mid]; int sum = 0;
for(int i = 1; i <= m; ++i) if(v[i] >= mid) can[i] = 0; else ++sum;
if(check(sum) <= n + 1) {ans = mid; l = mid + 1;}
else r = mid - 1;
for(int i = 1; i <= m; ++i) can[i] = 1;
}
if(ans == 1e9 + 1) puts("AK");
else print(ans);
return 0;
}