problem1 link

如果两个循环之内可以跳完,那么我们只要让这些步数之内的数字组成两个数字$p,q,p\leq q$,使得$p,q,x$组成三角形即可($p+q\geq x,p+x\geq q$)。

否则,若$x$是所有数字之和的很多倍,则一开始是一直直着向前跳$m$次,剩下$r=x-m\sum_{i=0}^{n-1}t_{i}$,然后找到一个前缀和大于等于$r$即可。

problem2 link

对于某个节点$u$,假如最后一定选择该节点,那么对于节点$p$,若选它,那么$p$到$u$路径上的点都必须选,这样就成了一个最大权闭合图问题。可以用最小割来计算。

problem3 link

对于不同的素数,可以分开考虑。

对于某一个素数p:用$min[i],max[i]$计算$n$个数字中每个数字最少最多含有多少个$p$。然后第$x$个数字含有的$p$要么取$min[x]$,要么取$max[x]$,因此可用2sat解决。

 

code for problem1

#include <algorithm>
#include <vector>

class PeriodicJumping {
 public:
  int minimalTime(int x, const std::vector<int> &jumps) {
    std::vector<int> copys = jumps;
    int n = static_cast<int>(copys.size());
    for (int i = 0; i < n; ++i) {
      copys.emplace_back(copys[i]);
    }
    n *= 2;
    if (x < 0) {
      x *= -1;
    }
    if (x == 0) {
      return 0;
    }
    long long s = 0;
    int max_jump = 0;
    for (int i = 0; i < n; ++i) {
      max_jump = std::max(max_jump, copys[i]);
      s += copys[i];
      long long min = std::max(0ll, max_jump - (s - max_jump));
      if (min <= x && x <= s) return i + 1;
    }
    int result = static_cast<int>(x / s * n);
    int remain = x % s;
    for (int i = 0; i < n && remain > 0; ++i) {
      remain -= copys[i];
      ++result;
    }
    return result;
  }
};

code for problem2

#include <limits>
#include <memory>
#include <unordered_map>
#include <vector>

template <typename FlowType>
class MaxFlowSolver {
  static constexpr FlowType kMaxFlow = std::numeric_limits<FlowType>::max();
  static constexpr FlowType kZeroFlow = static_cast<FlowType>(0);
  struct node {
    int v;
    int next;
    FlowType cap;
  };

 public:
  int VertexNumber() const { return used_index_; }

  FlowType MaxFlow(int source, int sink) {
    source = GetIndex(source);
    sink = GetIndex(sink);

    int n = VertexNumber();
    std::vector<int> pre(n);
    std::vector<int> cur(n);
    std::vector<int> num(n);
    std::vector<int> h(n);
    for (int i = 0; i < n; ++i) {
      cur[i] = head_[i];
      num[i] = 0;
      h[i] = 0;
    }
    int u = source;
    FlowType result = 0;
    while (h[u] < n) {
      if (u == sink) {
        FlowType min_cap = kMaxFlow;
        int v = -1;
        for (int i = source; i != sink; i = edges_[cur[i]].v) {
          int k = cur[i];
          if (edges_[k].cap < min_cap) {
            min_cap = edges_[k].cap;
            v = i;
          }
        }
        result += min_cap;
        u = v;
        for (int i = source; i != sink; i = edges_[cur[i]].v) {
          int k = cur[i];
          edges_[k].cap -= min_cap;
          edges_[k ^ 1].cap += min_cap;
        }
      }
      int index = -1;
      for (int i = cur[u]; i != -1; i = edges_[i].next) {
        if (edges_[i].cap > 0 && h[u] == h[edges_[i].v] + 1) {
          index = i;
          break;
        }
      }
      if (index != -1) {
        cur[u] = index;
        pre[edges_[index].v] = u;
        u = edges_[index].v;
      } else {
        if (--num[h[u]] == 0) {
          break;
        }
        int k = n;
        cur[u] = head_[u];
        for (int i = head_[u]; i != -1; i = edges_[i].next) {
          if (edges_[i].cap > 0 && h[edges_[i].v] < k) {
            k = h[edges_[i].v];
          }
        }
        if (k + 1 < n) {
          num[k + 1] += 1;
        }
        h[u] = k + 1;
        if (u != source) {
          u = pre[u];
        }
      }
    }
    return result;
  }

  MaxFlowSolver() = default;

  void Clear() {
    edges_.clear();
    head_.clear();
    vertex_indexer_.clear();
    used_index_ = 0;
  }

  void InsertEdge(int from, int to, FlowType cap) {
    from = GetIndex(from);
    to = GetIndex(to);
    AddEdge(from, to, cap);
    AddEdge(to, from, kZeroFlow);
  }

 private:
  int GetIndex(int idx) {
    auto iter = vertex_indexer_.find(idx);
    if (iter != vertex_indexer_.end()) {
      return iter->second;
    }
    int map_idx = used_index_++;
    head_.push_back(-1);
    return vertex_indexer_[idx] = map_idx;
  }

  void AddEdge(int from, int to, FlowType cap) {
    node p;
    p.v = to;
    p.cap = cap;
    p.next = head_[from];
    head_[from] = static_cast<int>(edges_.size());
    edges_.emplace_back(p);
  }

  std::vector<node> edges_;
  std::vector<int> head_;

  std::unordered_map<int, int> vertex_indexer_;
  int used_index_ = 0;
};

class DoubleTree {
 public:
  int maximalScore(const std::vector<int> &a, const std::vector<int> &b,
                   const std::vector<int> &c, const std::vector<int> &d,
                   const std::vector<int> &score) {
    int n = static_cast<int>(a.size() + 1);
    std::vector<std::vector<int>> g1(n);
    std::vector<std::vector<int>> g2(n);
    for (int i = 0; i < n - 1; ++i) {
      g1[a[i]].push_back(b[i]);
      g1[b[i]].push_back(a[i]);
      g2[c[i]].push_back(d[i]);
      g2[d[i]].push_back(c[i]);
    }

    constexpr int kInfiniteFlow = 1000000;
    std::unique_ptr<MaxFlowSolver<int>> solver(new MaxFlowSolver<int>());
    int result = 0;
    for (int root = 0; root < n; ++root) {
      std::vector<int> father1(n);
      std::vector<int> father2(n);
      Dfs(root, -1, father1, g1);
      Dfs(root, -1, father2, g2);
      solver->Clear();
      int source = -1;
      int sink = -2;
      int s = 0;
      for (int i = 0; i < n; ++i) {
        if (score[i] > 0) {
          s += score[i];
          solver->InsertEdge(source, i, score[i]);
        } else {
          solver->InsertEdge(i, sink, -score[i]);
        }
        if (i != root) {
          solver->InsertEdge(i, father1[i], kInfiniteFlow);
          solver->InsertEdge(i, father2[i], kInfiniteFlow);
        }
      }
      result = std::max(result, s - solver->MaxFlow(source, sink));
    }
    return result;
  }

 private:
  void Dfs(int u, int pre, std::vector<int> &father,
           const std::vector<std::vector<int>> &g) {
    father[u] = pre;
    for (auto e : g[u]) {
      if (e != pre) {
        Dfs(e, u, father, g);
      }
    }
  }
};

code for problem3

#include <algorithm>
#include <memory>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <vector>

class StronglyConnectedComponentSolver {
 public:
  StronglyConnectedComponentSolver() = default;

  void Initialize(int n) { edges_.resize(n); }

  std::vector<int> Solve() {
    total_ = static_cast<int>(edges_.size());
    if (total_ == 0) {
      return {};
    }
    visited_.resize(total_, false);
    low_indices_.resize(total_, 0);
    dfs_indices_.resize(total_, 0);
    connected_component_indices_.resize(total_, 0);
    for (int i = 0; i < total_; ++i) {
      if (0 == dfs_indices_[i]) {
        Dfs(i);
      }
    }
    return connected_component_indices_;
  }

  int VertexNumber() const { return static_cast<int>(edges_.size()); }

  inline void AddEdge(int from, int to) { edges_[from].push_back(to); }

  const std::vector<int> &Tos(int u) const { return edges_[u]; }

 private:
  void Dfs(const int u) {
    low_indices_[u] = dfs_indices_[u] = ++index_;
    stack_.push(u);
    visited_[u] = true;
    for (auto v : edges_[u]) {
      if (0 == dfs_indices_[v]) {
        Dfs(v);
        low_indices_[u] = std::min(low_indices_[u], low_indices_[v]);
      } else if (visited_[v]) {
        low_indices_[u] = std::min(low_indices_[u], dfs_indices_[v]);
      }
    }
    if (dfs_indices_[u] == low_indices_[u]) {
      int v = 0;
      do {
        v = stack_.top();
        stack_.pop();
        visited_[v] = false;
        connected_component_indices_[v] = connected_component_index_;
      } while (u != v);
      ++connected_component_index_;
    }
  }

  std::vector<std::vector<int>> edges_;
  int total_ = 0;
  std::vector<bool> visited_;
  std::vector<int> low_indices_;
  std::vector<int> dfs_indices_;
  std::stack<int> stack_;
  int index_ = 0;
  int connected_component_index_ = 0;
  std::vector<int> connected_component_indices_;
};

class TwoSatisfiabilitySolver {
 public:
  void Initialize(int total_vertex_number) {
    scc_solver_.Initialize(total_vertex_number);
  }

  // If idx1 is type1, then idx2 must be type2.
  void AddConstraint(int idx1, bool type1, int idx2, bool type2) {
    int from = idx1 * 2 + (type1 ? 1 : 0);
    int to = idx2 * 2 + (type2 ? 1 : 0);
    scc_solver_.AddEdge(from, to);
  }

  void AddConflict(int idx1, bool type1, int idx2, bool type2) {
    AddConstraint(idx1, type1, idx2, !type2);
    AddConstraint(idx2, type2, idx1, !type1);
  }

  void AddLead(int idx1, bool type1, int idx2, bool type2) {
    AddConstraint(idx1, type1, idx2, type2);
    AddConstraint(idx2, !type2, idx1, !type1);
  }

  // The idx must not be type
  void SetFalse(int idx, bool type) { SetTrue(idx, !type); }

  // The idx must be type
  void SetTrue(int idx, bool type) { AddConstraint(idx, !type, idx, type); }

  bool ExistSolution() {
    if (scc_indices_.empty()) {
      scc_indices_ = scc_solver_.Solve();
      total_scc_number_ =
          *std::max_element(scc_indices_.begin(), scc_indices_.end()) + 1;
    }
    for (int i = 0; i < scc_solver_.VertexNumber() / 2; ++i) {
      if (scc_indices_[i * 2] == scc_indices_[i * 2 + 1]) {
        return false;
      }
    }
    return true;
  }

  std::vector<bool> GetOneSolution() {
    if (!ExistSolution()) {
      return {};
    }
    BuildNewGraph();
    TopSort();
    int total = scc_solver_.VertexNumber();
    std::vector<bool> result(total / 2);
    for (int e = 0; e < total / 2; ++e) {
      if (last_color_[scc_indices_[e * 2]] == 0) {
        result[e] = false;
      } else {
        result[e] = true;
      }
    }
    return std::move(result);
  }

 private:
  void BuildNewGraph() {
    new_edges_.resize(total_scc_number_);
    new_graph_node_in_degree_.resize(total_scc_number_, 0);
    int total = scc_solver_.VertexNumber();
    for (int i = 0; i < total; ++i) {
      int scc0 = scc_indices_[i];
      for (auto e : scc_solver_.Tos(i)) {
        int scc1 = scc_indices_[e];
        if (scc0 != scc1 &&
            new_edges_[scc1].find(scc0) == new_edges_[scc1].end()) {
          new_edges_[scc1].insert(scc0);
          ++new_graph_node_in_degree_[scc0];
        }
      }
    }
  }

  void TopSort() {
    std::vector<int> conflict(total_scc_number_);
    int total = scc_solver_.VertexNumber() / 2;
    for (int i = 0; i < total; ++i) {
      conflict[scc_indices_[i * 2]] = scc_indices_[i * 2 + 1];
      conflict[scc_indices_[i * 2 + 1]] = scc_indices_[i * 2];
    }
    last_color_.resize(total_scc_number_, -1);
    std::stack<int> st;
    for (int i = 0; i < total_scc_number_; ++i) {
      if (0 == new_graph_node_in_degree_[i]) {
        st.push(i);
      }
    }
    while (!st.empty()) {
      int u = st.top();
      st.pop();
      if (last_color_[u] == -1) {
        last_color_[u] = 0;
        last_color_[conflict[u]] = 1;
      }
      for (auto e : new_edges_[u]) {
        int cur = --new_graph_node_in_degree_[e];
        if (cur == 0) {
          st.push(e);
        }
      }
    }
  }

  std::vector<int> scc_indices_;
  int total_scc_number_ = 0;
  std::vector<std::unordered_set<int>> new_edges_;
  std::vector<int> new_graph_node_in_degree_;
  std::vector<int> last_color_;

  StronglyConnectedComponentSolver scc_solver_;
};

class GCDLCM {
 public:
  std::string possible(int n, const std::string &type,
                       const std::vector<int> &A, const std::vector<int> &B,
                       const std::vector<int> &C) {
    std::unordered_set<int> primes;
    for (auto c : C) {
      for (int i = 2; i * i <= c; ++i) {
        if (c % i == 0) {
          primes.insert(i);
          while (c % i == 0) {
            c /= i;
          }
        }
      }
      if (c > 1) {
        primes.insert(c);
      }
    }
    int m = static_cast<int>(C.size());
    auto Check = [&](int p) {
      std::vector<int> min(n, 0);
      std::vector<int> max(n, 1000);
      std::vector<int> number(m, 0);

      for (int i = 0; i < m; ++i) {
        int t = C[i];
        while (t % p == 0) {
          ++number[i];
          t /= p;
        }
        if (type[i] == 'G') {
          min[A[i]] = std::max(min[A[i]], number[i]);
          min[B[i]] = std::max(min[B[i]], number[i]);
        } else {
          max[A[i]] = std::min(max[A[i]], number[i]);
          max[B[i]] = std::min(max[B[i]], number[i]);
        }
      }
      for (int i = 0; i < n; ++i) {
        if (min[i] > max[i]) {
          return false;
        }
      }
      std::unique_ptr<TwoSatisfiabilitySolver> solver(
          new TwoSatisfiabilitySolver());
      solver->Initialize(n * 2);
      for (int i = 0; i < m; i++) {
        int u = A[i];
        int v = B[i];
        if (type[i] == 'G') {
          bool x = min[u] > number[i];
          bool y = min[v] > number[i];
          if (x && y) {
            return false;
          } else if (x) {
            if (min[v] != max[v]) {
              solver->SetTrue(v, false);
            }
          } else if (y) {
            if (min[u] != max[u]) {
              solver->SetTrue(u, false);
            }
          } else {
            if (min[v] != max[v] && min[u] != max[u]) {
              solver->AddConstraint(v, true, u, false);
              solver->AddConstraint(u, true, v, false);
            }
          }
        } else {
          bool x = max[u] < number[i];
          bool y = max[v] < number[i];
          if (x && y) {
            return false;
          } else if (x) {
            if (min[v] != max[v]) {
              solver->SetTrue(v, true);
            }
          } else if (y) {
            if (min[u] != max[u]) {
              solver->SetTrue(u, true);
            }
          } else {
            if (min[v] != max[v] && min[u] != max[u]) {
              solver->AddConstraint(v, false, u, true);
              solver->AddConstraint(u, false, v, true);
            }
          }
        }
      }
      return solver->ExistSolution();
    };
    for (auto p : primes) {
      if (!Check(p)) {
        return "Solution does not exist";
      }
    }
    return "Solution exists";
  }
};