Codeforces Round #545 C. Museums Tour

https://codeforces.com/contest/1137/problem/C


We do not need to use GCD or something. We prepare the graph with N×D vertices and do SCC on it. Then, we can do dynamic programming on the contracted graph. The total time complexity is O(ND), but the hidden constant is large.

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <set>

using namespace std;

struct strong {
  int N, K;
  vector<vector<int>> G, RG;
  vector<int> C;
  vector<bool> used;
  vector<int> post;
  vector<pair<int, int>> E;

  strong(int n) : N(n), K(0), G(n), RG(n), C(n, -1), used(n) {}

  void add(int u, int v) {
    G[u].push_back(v);
    RG[v].push_back(u);
  }

  void build() {
    for (int i = 0; i < N; i++) {
      dfs(i);
    }
    reverse(post.begin(), post.end());
    for (int i : post) {
      if (C[i] == -1) {
        dfs2(i, K++);
      }
    }
    for (int i = 0; i < N; i++) {
      for (int k : G[i]) {
        if (C[i] != C[k]) {
          E.emplace_back(C[i], C[k]);
        }
      }
    }
    sort(E.begin(), E.end());
  }

  void dfs(int u) {
    if (used[u]) return;
    used[u] = true;
    for (int v : G[u]) {
      dfs(v);
    }
    post.push_back(u);
  }

  void dfs2(int u, int k) {
    if (C[u] != -1) return;
    C[u] = k;
    for (int v : RG[u]) {
      dfs2(v, k);
    }
  }
};

int main() {
  cin.tie(nullptr);
  ios::sync_with_stdio(false);
  int N, M, D;
  cin >> N >> M >> D;
  strong scc(N * D);
  for (int i = 0; i < M; i++) {
    int u, v;
    cin >> u >> v;
    u--; v--;
    for (int j = 0; j < D; j++) {
      scc.add(u * D + j, v * D + (j + 1) % D);
    }
  }
  vector<string> S(N);
  for (int i = 0; i < N; i++) {
    cin >> S[i];
  }
  scc.build();
  vector<int> dp(scc.K, -1e9);
  vector<int> cnt(scc.K);
  for (int i = 0; i < N; i++) {
    set<int> st;
    for (int j = 0; j < D; j++) {
      if (S[i][j] == '1') {
        st.insert(scc.C[i * D + j]);
      }
    }
    for (int x : st) {
      cnt[x]++;
    }
  }
  dp[scc.C[0]] = 0;
  for (auto e : scc.E) {
    dp[e.second] = max(dp[e.second], dp[e.first] + cnt[e.first]);
  }
  int ans = 0;
  for (int i = 0; i < scc.K; i++) {
    ans = max(ans, dp[i] + cnt[i]);
  }
  cout << ans << '\n';
}