【题目链接】
这题有毒orz。
判断两个自动机是否有升级关系,BFS一次就行了orz。两个自动机都从0开始,同时走0,同时走1。如果一个自动机到达输出点,而另一个没到达,那么没有升级关系。
然后根据升级关系建图,Tarjan缩点,然后跑DAG上最长路就行了。
注意一个强联通内都是互相有升级关系的,跑最长路时要取size而不是取1,WA了一发...
/* Pigonometry */ #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 55, maxm = maxn * maxn, maxq = 10000, maxs = 10000; int n, head[maxn], cnt, vis[maxn][maxn], clo; int dfn[maxn], low[maxn], belong[maxn], size[maxn], tot, sta[maxs], top; int dp[maxn], mp[maxn][maxn], du[maxn], q[maxq]; bool ins[maxn]; struct _edge { int v, next; } g[maxm << 1]; struct _data { int x, y; }; inline int iread() { int f = 1, x = 0; char ch = getchar(); for(; ch < '0' || ch > '9'; ch = getchar()) f = ch == '-' ? -1 : 1; for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0'; return f * x; } struct automaton { int n, m, trans[maxn][2]; bool out[maxn]; void read() { n = iread(); m = iread(); for(int i = 1; i <= m; i++) out[iread()] = 1; for(int i = 0; i < n; i++) trans[i][0] = iread(), trans[i][1] = iread(); } } A[maxn]; inline void add(int u, int v) { g[cnt] = (_edge){v, head[u]}; head[u] = cnt++; } inline bool bfs(int s, int d) { static _data q[maxq]; clo++; int h = 0, t = 0; q[t++] = (_data){0, 0}; vis[0][0] = clo; while(h != t) { _data u = q[h++]; int x = u.x, y = u.y; if(A[s].out[x] && !A[d].out[y]) return 0; for(int i = 0; i < 2; i++) { int xx = A[s].trans[x][i], yy = A[d].trans[y][i]; if(vis[xx][yy] != clo) { vis[xx][yy] = clo; q[t++] = (_data){xx, yy}; } } } return 1; } inline void tarjan(int x) { dfn[x] = low[x] = ++clo; ins[sta[++top] = x] = 1; for(int i = head[x]; ~i; i = g[i].next) { int v = g[i].v; if(!dfn[v]) tarjan(v), low[x] = min(low[x], low[v]); else if(ins[v]) low[x] = min(low[x], dfn[v]); } if(dfn[x] == low[x]) { tot++; while(1) { int u = sta[top--]; belong[u] = tot; size[tot]++; ins[u] = 0; if(u == x) break; } } } inline int topo() { for(int i = 1; i <= tot; i++) for(int j = 1; j <= tot; j++) if(mp[i][j]) du[j]++; int h = 0, t = 0, res = 1; for(int i = 1; i <= tot; i++) if(!du[i]) dp[q[t++] = i] = size[i]; while(h != t) { int u = q[h++]; for(int i = 1; i <= tot; i++) if(mp[u][i] && dp[i] < dp[u] + size[i]) { dp[i] = dp[u] + size[i]; q[t++] = i; res = max(res, dp[i]); } } return res; } int main() { n = iread(); for(int i = 1; i <= n; i++) head[i] = -1, A[i].read(); cnt = clo = 0; for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) if(i ^ j && bfs(i, j)) add(i, j); clo = top = 0; for(int i = 1; i <= n; i++) if(!dfn[i]) tarjan(i); for(int u = 1; u <= n; u++) for(int i = head[u]; ~i; i = g[i].next) if(belong[u] != belong[g[i].v]) mp[belong[u]][belong[g[i].v]] = 1; printf("%d\n", topo()); return 0; }