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"; } };