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);
  }
};
posted @ 2018-12-22 18:04  朝拜明天19891101  阅读(413)  评论(0编辑  收藏  举报