1. 程式人生 > >topcoder srm 575 div1

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\ne 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

 

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