题意不太明确......
这题的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; }