topcoder srm 625 div1
阿新 • • 發佈:2018-11-03
problem1 link
假設第$i$種出現的次數為$n_{i}$,總個數為$m$,那麼排列數為$T=\frac{m!}{\prod_{i=1}^{26}(n_{i}!)}$
然後計算迴文的個數,只需要考慮前一半,得到個數為$R$,那麼答案為$\frac{R}{T}$.
為了防止數字太大導致越界,可以分解為質因子的表示方法。
problem2 link
假設終點所在的位置為$(tx,ty)$,那麼所有底面是$1x1$的格子$(x,y)$一定滿足$(x-tx)mod(3)=0,(y-ty)mod(3)=0$
把每個這樣的點拆成兩個點然後建立最小割的圖。
源點與所有的$b$相連,終點與匯點相連,流量為無窮,割邊不會在這裡產生。
如果不是洞,那麼這個格子拆成的兩個點流量為1,表示將這個格子設為洞。
每個格子向周圍連邊,流量為將中間的兩個格子設為洞的代價。
最後最小割就是答案。
code for problem1
#include <cmath> #include <string> #include <vector> class PalindromePermutations { public: double palindromeProbability(const std::string &word) { std::vector<int> h(26, 0); for (auto e : word) { ++h[e - 'a']; } int old_idx = -1; for (int i = 0; i < 26; ++i) { if (h[i] % 2 == 1) { if (old_idx != -1) { return 0.0; } old_idx = i; } } auto total = Compute(h); if (old_idx != -1) { --h[old_idx]; } for (auto &e : h) { e /= 2; } auto target = Compute(h); double result = 1.0; for (int i = 2; i < 50; ++i) { result *= std::pow(i, target[i] - total[i]); } return result; } private: std::vector<int> Compute(const std::vector<int> &h) { std::vector<int> result(50, 0); auto Add = [&](int x, int sgn) { for (int i = 2; i <= x; ++i) { int k = i; for (int j = 2; j * j <= k; ++j) { while (k % j == 0) { result[j] += sgn; k /= j; } } if (k != 1) { result[k] += sgn; } } }; int n = 0; for (auto e : h) { Add(e, -1); n += e; } Add(n, 1); return result; } };
code for problem2
#include <limits> #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 BlockTheBlockPuzzle { static constexpr int kInfinite = 1000000; public: int minimumHoles(const std::vector<std::string> &S) { MaxFlowSolver<int> solver; int n = static_cast<int>(S.size()); int source = -1; int sink = -2; int tx = -1, ty = -1; for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { if (S[i][j] == '$') { tx = i; ty = j; } } } auto P0 = [&](int i, int j) { return i * n + j; }; auto P1 = [&](int i, int j) { return i * n + j + n * n; }; for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { if (i % 3 == tx % 3 && j % 3 == ty % 3) { if (S[i][j] == '$') { solver.InsertEdge(P1(i, j), sink, kInfinite); } if (S[i][j] == 'b') { solver.InsertEdge(source, P0(i, j), kInfinite); } if (S[i][j] != 'H') { solver.InsertEdge(P0(i, j), P1(i, j), S[i][j] == '.' ? 1 : kInfinite); } if (i + 3 < n) { auto cost = GetCost(S, i + 1, j, i + 2, j); solver.InsertEdge(P1(i, j), P0(i + 3, j), cost); solver.InsertEdge(P1(i + 3, j), P0(i, j), cost); } if (j + 3 < n) { auto cost = GetCost(S, i, j + 1, i, j + 2); solver.InsertEdge(P1(i, j), P0(i, j + 3), cost); solver.InsertEdge(P1(i, j + 3), P0(i, j), cost); } } } } auto result = solver.MaxFlow(source, sink); if (result >= kInfinite) { return -1; } return result; } private: int GetCost(const std::vector<std::string> &s, int x1, int y1, int x2, int y2) { if (s[x1][y1] == 'b' || s[x2][y2] == 'b') { return kInfinite; } int ans = 0; if (s[x1][y1] == '.') { ++ans; } if (s[x2][y2] == '.') { ++ans; } return ans; } };