zoukankan      html  css  js  c++  java
  • topcoder srm 575 div1

    problem1 link

    如果$k$是先手必胜那么$f(k)=1$否则$f(k)=0$

    通过对前面小的数字的计算可以发现:(1)$f(2k+1)=0$,(2)$f(2^{2k+1})=0$,(3)其他情况都是1

    这个可以用数学归纳法证明

    problem2 link

    假设字符串的总长度为$n$

    首先,设$x_{k}$为位置$i$经过$k$ 次交换后仍然在$i$的概率,那么在其他位置$j(j e i)$的概率为$frac{x}{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}*P+frac{x_{k}}{n-1}*(T-P))*S_{i}$

    其中$S_{i}$表示位置$i$的数字。$P$表示任意选一个区间包含$i$的概率,$P=F_{i}=frac{2i(n-i+1)}{n(n+1)}$,而$T=sum_{i=1}^{n}F_{i}$

    problem3 link

    这个可以用最大流来解决。

    (1)将每个黑色的格子拆分成两个点,一个表示进入该格子,一个表示离开该格子。这两个点之间连边,流量为1。

    (2)将所有白色的格子,分为两类,第一类是列数为偶数的,第二类是列数为奇数的。源点向第一类连边,流量为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);
      }
    };
  • 相关阅读:
    逆元应用求组合数
    树的重心入门
    扫描线求面积的并,交
    涂抹果酱
    牧场的安排
    「SCOI2005」互不侵犯
    Network Coverage
    Linux命令传输文件
    VMware Workstation 与 Device/Credential Guard 不兼容.在禁用 Device/Credenti
    Springboot开启SpringSecurity
  • 原文地址:https://www.cnblogs.com/jianglangcaijin/p/10161916.html
Copyright © 2011-2022 走看看