QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#414615#2683. British MenushepherdWA 1ms3832kbC++205.9kb2024-05-19 12:05:292024-05-19 12:05:30

Judging History

你现在查看的是最新测评结果

  • [2024-05-19 12:05:30]
  • 评测
  • 测评结果:WA
  • 用时:1ms
  • 内存:3832kb
  • [2024-05-19 12:05:29]
  • 提交

answer

#include <bits/stdc++.h>

#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")

#ifdef LLOCAL
#include "./debug.h"
#else
#define var(...)
#define debugArr(...)
#endif

using namespace std;

#define len(a) static_cast<int>((a).size())
#define present(c, x) (c.find(x) != c.end())
#define printDecimal(d) std::cout << std::setprecision(d) << std::fixed

using ll = long long;
using ull = unsigned long long;
using ld = long double;
constexpr const int iinf = 1e9 + 7;
constexpr const ll inf = 1e18;
static constexpr const ll mod = 1000000007;

template <typename Fun>
class y_combinator_result {
  Fun fun_;

 public:
  template <typename T>
  explicit y_combinator_result(T&& fun) : fun_{std::forward<T>(fun)} {}

  template <typename... ArgTs>
  decltype(auto) operator()(ArgTs&&... args) {
    return fun_(std::ref(*this), std::forward<ArgTs>(args)...);
  }
};

template <typename Fun>
decltype(auto) y_combinator(Fun&& fun) {
  return y_combinator_result<std::decay_t<Fun>>(std::forward<Fun>(fun));
}

int main() {
  std::ios_base::sync_with_stdio(false);
  cin.tie(0);
  int n, m;
  cin >> n >> m;
  vector<vector<int>> graph(n), rev_graph(n);
  for (int i = 0; i < m; i++) {
    int a, b;
    cin >> a >> b;
    graph[--a].push_back(--b);
    rev_graph[b].push_back(a);
  }
  // find all scc
  vector<bool> visited(n, false);
  vector<int> order;
  auto dfs1 = y_combinator([&](auto self, int curr) -> void {
    visited[curr] = true;
    for (const auto& neighbor : graph[curr]) {
      if (!visited[neighbor]) self(neighbor);
    }
    order.push_back(curr);
  });
  for (int i = 0; i < n; i++) {
    if (!visited[i]) {
      dfs1(i);
    }
  }
  fill(visited.begin(), visited.end(), false);
  reverse(order.begin(), order.end());
  vector<int> comp(n, -1);
  vector<vector<int>> comps;
  int comp_no = 0;
  auto dfs2 = y_combinator([&](auto self, int curr) -> void {
    visited[curr] = true;
    comp[curr] = comp_no;
    comps.back().push_back(curr);
    for (const auto& neighbor : rev_graph[curr]) {
      if (!visited[neighbor]) {
        self(neighbor);
      }
    }
  });
  for (auto i : order) {
    if (!visited[i]) {
      comps.emplace_back();
      dfs2(i);
      sort(comps.back().begin(), comps.back().end());
      assert(len(comps.back()) <= 5);
      comp_no++;
    }
  }
  vector<vector<pair<int, int>>> comp_edges(comp_no);
  map<pair<int, int>, vector<pair<int, int>>> between_comp;
  vector<int> p(n);
  for (int i = 0; i < n; i++) {
    p[i] = lower_bound(comps[comp[i]].begin(), comps[comp[i]].end(), i) -
           comps[comp[i]].begin();
  }
  for (int i = 0; i < n; i++) {
    for (const auto& neighbor : graph[i]) {
      if (comp[neighbor] == comp[i]) {
        comp_edges[comp[i]].emplace_back(p[i], p[neighbor]);
      } else {
        between_comp[make_pair(comp[i], comp[neighbor])].emplace_back(
            p[i], p[neighbor]);
      }
    }
  }
  vector<vector<vector<int>>> lookup(
      n, vector<vector<int>>(5, vector<int>(5, iinf)));

  // do bitmask dp stuff within each scc
  for (int ci = 0; ci < comp_no; ci++) {
    if (len(comps[ci]) == 1) {
      lookup[ci][0][0] = 1;
    } else {
      vector<vector<int>> sg(len(comps[ci]));
      for (const auto& [u, v] : comp_edges[ci]) {
        sg[u].push_back(v);
      }
      for (int i = 0; i < len(comps[ci]); i++) {
        vector<vector<bool>> seen(1 << len(comps[ci]),
                                  vector<bool>(len(comps[ci])));
        queue<pair<int, int>> q;
        seen[1 << i][i] = true;
        q.emplace(1 << i, i);
        while (!q.empty()) {
          auto [mask, pos] = q.front();
          q.pop();
          lookup[ci][i][pos] =
              min(lookup[ci][i][pos], __builtin_popcount(mask));
          for (const auto& neighbor : sg[pos]) {
            if (!(mask & (1 << neighbor)) &&
                !seen[mask | (1 << neighbor)][neighbor]) {
              seen[mask | (1 << neighbor)][neighbor] = true;
              q.emplace(mask | (1 << neighbor), neighbor);
            }
          }
        }
      }
    }
  }
  // compress scc
  vector<vector<int>> adj_scc(comp_no);
  vector<int> indegree(comp_no);
  for (int curr = 0; curr < n; curr++) {
    for (const auto& neighbor : graph[curr]) {
      int ru = comp[curr], rv = comp[neighbor];
      if (ru != rv) {
        adj_scc[ru].push_back(rv);
      }
    }
  }
  queue<int> q;
  for (int i = 0; i < comp_no; i++) {
    sort(adj_scc[i].begin(), adj_scc[i].end());
    adj_scc[i].erase(unique(begin(adj_scc[i]), end(adj_scc[i])),
                     adj_scc[i].end());
    for (const auto& neighbor : adj_scc[i]) {
      indegree[neighbor]++;
    }
  }
  for (int i = 0; i < comp_no; i++) {
    if (indegree[i] == 0) {
      q.push(i);
    }
  }
  vector<int> top_order;
  while (!q.empty()) {
    auto curr = q.front();
    q.pop();
    top_order.push_back(curr);
    for (const auto& neighbor : adj_scc[curr]) {
      if (--indegree[neighbor] == 0) {
        q.push(neighbor);
      }
    }
  }
  assert(len(top_order) == comp_no);
  int ret = 0;
  vector<vector<int>> dp(comp_no, vector<int>(5, -1));
  auto solve = y_combinator([&](auto self, int node, int comp_idx) -> int {
    if (dp[comp_idx][node] != -1) return dp[comp_idx][node];
    for (int i = 0; i < len(comps[comp_idx]); i++) {
      dp[comp_idx][node] = max(dp[comp_idx][node], lookup[comp_idx][node][i]);
    }
    for (const auto& neighbor : adj_scc[comp_idx]) {
      for (const auto& [from, to] :
           between_comp[make_pair(comp_idx, neighbor)]) {
        dp[comp_idx][node] =
            max(dp[comp_idx][node],
                self(to, neighbor) + lookup[comp_idx][node][from]);
      }
    }
    return dp[comp_idx][node];
  });
  for (auto ci : top_order) {
    for (auto node : comps[ci]) {
      ret = max(ret, solve(p[node], ci));
    }
  }
  cout << ret << '\n';
}

Details

Tip: Click on the bar to expand more detailed information

Test #1:

score: 100
Accepted
time: 1ms
memory: 3624kb

input:

10 6
7 8
4 2
8 6
5 1
4 1
4 5

output:

3

result:

ok single line: '3'

Test #2:

score: 0
Accepted
time: 1ms
memory: 3556kb

input:

10 10
1 3
8 9
6 10
1 2
7 9
10 9
5 1
2 5
8 6
7 8

output:

5

result:

ok single line: '5'

Test #3:

score: 0
Accepted
time: 1ms
memory: 3620kb

input:

10 8
7 6
4 2
10 6
4 5
2 4
3 2
6 10
2 1

output:

4

result:

ok single line: '4'

Test #4:

score: 0
Accepted
time: 0ms
memory: 3620kb

input:

10 19
3 6
9 10
7 9
9 8
8 7
5 6
3 8
6 9
5 9
2 6
6 8
1 4
6 7
6 10
3 9
10 7
4 9
10 8
1 8

output:

6

result:

ok single line: '6'

Test #5:

score: 0
Accepted
time: 0ms
memory: 3584kb

input:

10 19
2 7
8 10
9 8
3 10
8 9
4 5
2 10
1 8
9 6
1 9
4 6
3 2
5 9
5 2
10 7
5 10
7 6
6 9
4 7

output:

8

result:

ok single line: '8'

Test #6:

score: -100
Wrong Answer
time: 1ms
memory: 3832kb

input:

10 18
3 6
2 10
2 5
5 3
4 2
1 5
7 9
10 7
8 6
3 2
4 8
8 9
3 7
7 8
1 4
3 1
5 1
3 9

output:

7

result:

wrong answer 1st lines differ - expected: '9', found: '7'