Codeforces 1137C Museums Tour (強連通分量, DP)
阿新 • • 發佈:2019-03-20
blank ont int std queue 假設 ons memset its
題意和思路看這篇博客就行了:https://www.cnblogs.com/cjyyb/p/10507937.html
有個問題需要註意:對於每個scc,只需要考慮進入這個scc的時間即可,其實和從哪個點進沒有關系,因為scc內每個點都可以互相到達,所以只需記錄時間就囊括了所有的情況,比如時間3從1號點進和時間4從2號點進是等價的,這也是為什麽可以隨便選擇一顆生成樹的原因。對於scc的出邊,邊的長度是val[u] + val[v] - 1,因為假設從scc x的根 到點scc y的點v,時間是val[u] + 1,而scc y的根到v的距離是val[v],所以要求原裝態需要減去這個。當然,這個邊需要對兩個scc的gcd的gcd取模,以判斷從這條邊到下一條邊可以到達的狀態。
代碼:
#include <bits/stdc++.h> using namespace std; const int maxn = 100010; int head[maxn], Next[maxn * 2], ver[maxn * 2], tot; int heade[maxn], Nexte[maxn * 2 * 50], edgee[maxn * 2 * 50], vere[maxn * 2 * 50], tote, cnt; int n, m, D, GCD, g[maxn], f[maxn][51], pre[maxn][51], deg[maxn], val[maxn], c[maxn]; int dfn[maxn], low[maxn], num, top, Stack[maxn]; char v[maxn][51]; bool vis[maxn], ins[maxn]; vector<int> scc[maxn]; void add(int x, int y) { ver[++tot] = y;Next[tot] = head[x];head[x] = tot; } void adde(int x, int y, int z) { vere[++tote] = y, edgee[tote] = z, Nexte[tote] = heade[x], heade[x] = tote, deg[y]++; } void solve(int x, int p) { val[x] = p, vis[x] = 1; for (int i = head[x]; i; i = Next[i]) { int y = ver[i]; if(c[y] != cnt) continue; if(!vis[y]) solve(y, p + 1); else GCD = __gcd(GCD, abs(p + 1 - val[y])); } } void tarjan(int x) { dfn[x] = low[x] = ++num; Stack[++top] = x, ins[x] = 1; for (int i = head[x]; i; i = Next[i]) { if (!dfn[ver[i]]) { tarjan(ver[i]); low[x] = min(low[x], low[ver[i]]); } else if (ins[ver[i]]) low[x] = min(low[x], dfn[ver[i]]); } if (dfn[x] == low[x]) { cnt++; int y; do { y = Stack[top--], ins[y] = 0; c[y] = cnt, scc[cnt].push_back(y); } while(x != y); GCD = D, solve(x, 0); g[cnt] = GCD; for (int i = 0; i < GCD; i++) for (int j = 0; j < scc[cnt].size(); j++) { for (int k = i; k < D; k += GCD) if(v[scc[cnt][j]][k] == ‘1‘) { v[scc[cnt][j]][i] = ‘1‘; break; } } for (int i = 0; i < GCD; i++) for (int j = 0; j < scc[cnt].size(); j++) { if(v[scc[cnt][j]][(val[scc[cnt][j]] + i) % GCD] == ‘1‘) pre[cnt][i]++; } } } void dp(void) { int ans = 0; memset(f, -0x3f, sizeof(f)); f[c[1]][0] = pre[c[1]][0]; queue<int> q; for (int i = 1; i <= cnt; i++) { if (!deg[i]) q.push(i); } while(!q.empty()) { int x = q.front(); q.pop(); for (int i = heade[x]; i; i = Nexte[i]) { int y = vere[i]; deg[y]--; if(deg[y] == 0) q.push(y); } for (int i = heade[x]; i; i = Nexte[i]) { for (int j = 0; j < D; j++) { int y = vere[i], z = edgee[i]; f[y][(z + j) % D] = max(f[y][(z + j) % D], f[x][j] + pre[y][(z + j) % g[y]]); } } for (int i = 0; i < D; i++) ans = max(ans, f[x][i]); } printf("%d\n", ans); } int main() { int x, y; scanf("%d%d%d", &n, &m, &D); for (int i = 1; i <= m; i++) { scanf("%d%d", &x, &y); add(x, y); } for (int i = 1; i <= n; i++) scanf("%s", v[i]); for (int i = 1; i <= n; i++) { if(!dfn[i]) tarjan(i); } for (int j = 1; j <= n; j++) for (int i = head[j]; i; i = Next[i]) { int y = ver[i]; if(c[j] == c[y]) continue; int dd = __gcd(g[c[j]], g[c[y]]); int d = (val[j] - val[y] + 1 + D) % D; for (int k = d % dd; k < D; k += dd) { adde(c[j], c[y], k); } } dp(); }
Codeforces 1137C Museums Tour (強連通分量, DP)