topcoder srm 575 div1 [FINISHED]
problem1 link
如果$k$是先手必胜那么$f(k)=1$否则$f(k)=0$
可以发现:(1)$f(2k+1)=0$,(2)$f(2^{2k+1})=0$,(3)其他情况都是1
这个可以用数学归纳法证明
首先,$n \leq 6$时成立,$f(1)=0,f(2)=0,f(3)=0, f(4)=1, f(5)=0, f(6)=1$
当$n>6$时,将数字分为四类,它们的转移如下:
problem2 link
假设字符串的总长度为$n$
首先,设$x_{k}$为位置$i$经过$k$ 次交换后仍然在$i$的概率,那么在其他位置$j(j\ne i)$的概率为$\frac{1-x_{k}}{n-1}$(它在其他位置每个位置的概率是一样大的).可以得到关于$x_{k}$的转移方程$x_{0}=1, x_{k}=x_{k-1}*\frac{C_{n-1}^{2}}{C_{n}^{2}}+(1-x_{k-1})*\frac{1}{C_{n}^{2}}$
计算出了$x_{k}$之后。对于$[1,n]$的某个位置$i$,其对答案的贡献为$G(i)=(x_{k}*F_{i}+\frac{1-x_{k}}{n-1}*(T-F_{i}))*S_{i}$
其中$S_{i}$表示位置$i$的数字。$F_{i}$表示任意选一个区间包含$i$的概率,$F_{i}=\frac{2i(n-i+1)}{n(n+1)}$,而$T=\sum_{i=1}^{n}F_{i}$
problem3 link
这个可以用最大流来解决。
(1)将每个黑色的格子拆分成两个点,一个表示进入该格子,一个表示离开该格子。这两个点之间连边,流量为1。
(2)将所有白色的格子(不是'X'的,'X'的不需要考虑),分为两类,第一类是列数为偶数的,第二类是列数为奇数的。源点向第一类连边,流量为1;第二类向汇点连边,流量为1。另外,第一类向周围的四个黑色格子拆成的第一个连边,黑色格子拆成的第二个向第二类连边。
最后求最大流即可。
code for problem1
#include <string> class TheNumberGameDivOne { public: std::string find(long long n) { if (IsFirstWin(n)) { return "John"; } return "Brus"; } private: bool IsFirstWin(long long n) { if (n == 1 || n % 2 == 1) { return false; } int c = 0; while (n % 2 == 0) { ++c; n /= 2; } if (n == 1 && c % 2 == 1) { return false; } return true; } };
code for problem2
#include <string> #include <vector> class TheSwapsDivOne { public: double find(const std::vector<std::string> &seq, int k) { int n = 0; int sum = 0; for (const auto &e : seq) { n += static_cast<int>(e.size()); for (char c : e) { sum += c - '0'; } } auto Get = [&](int t) { return 2.0 * t * (n - t + 1) / n / (n + 1); }; double sum_rate = 0.0; for (int i = 1; i <= n; ++i) { sum_rate += Get(i); } double p = 1.0 * (n - 2) / n; double q = 2.0 / n / (n - 1); double x = 1.0; for (int i = 1; i <= k; ++i) { x = p * x + q * (1 - x); } double result = 0; int idx = 0; for (const auto &e : seq) { for (size_t i = 0; i < e.size(); ++i) { ++idx; int d = e[i] - '0'; double r = Get(idx); result += (x * r + (1 - x) / (n - 1) * (sum_rate - r)) * d; } } return result; } };
code for problem3
#include <limits> #include <string> #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 TheTilesDivOne { public: int find(const std::vector<std::string> &board) { MaxFlowSolver<int> solver; int n = static_cast<int>(board.size()); int m = static_cast<int>(board[0].size()); auto GetWhite = [&](int x, int y) { return x * m + y; }; auto GetBlackIn = [&](int x, int y) { return GetWhite(x, y); }; auto GetBlackOut = [&](int x, int y) { return GetWhite(x, y) + n * m; }; auto Valid = [&](int x, int y) { return 0 <= x && x < n && 0 <= y && y < m && board[x][y] != 'X'; }; int source = -1; int sink = -2; const int kDirX[] = {-1, 0, 1, 0}; const int kDirY[] = {0, 1, 0, -1}; for (int i = 0; i < n; ++i) { for (int j = i & 1; j < m; j += 2) { if (Valid(i, j)) { int in = GetBlackIn(i, j); int out = GetBlackOut(i, j); solver.InsertEdge(in, out, 1); for (int k = 0; k < 4; ++k) { int kx = i + kDirX[k]; int ky = j + kDirY[k]; if (Valid(kx, ky)) { if (kx % 2 == 0) { solver.InsertEdge(GetWhite(kx, ky), in, 1); } else { solver.InsertEdge(out, GetWhite(kx, ky), 1); } } } } } } for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { if ((i + j) % 2 == 1 && Valid(i, j)) { if (i % 2 == 0) { solver.InsertEdge(source, GetWhite(i, j), 1); } else { solver.InsertEdge(GetWhite(i, j), sink, 1); } } } } return solver.MaxFlow(source, sink); } };