zoukankan      html  css  js  c++  java
  • 2014百度之星复赛解题报告:The Game of Coins

    The Game of Coins
    时间限制:10s  内存限制:64MB

    问题描述
    CirnoMarisa经常在一起玩抛硬币的游戏,每次由Cirno先选择正面(H)或反面(T),然后抛一次硬币,如果结果和Cirno的选择一致,则Cirno赢,如果结果相反,则Marisa赢。有一天,MarisaCirno说,过去的玩法都弱爆了,给Cirno介绍了一种新的玩法。现在Cirno每次选择一个长度为n的由HT组成的字符串,然后Marisa也选择一个不同的字符串,随后她们不断抛硬币,直到其中一个人选择的字符串和最后n次抛硬币的结果相匹配,匹配的人将获胜。玩了一段时间后,Cirno发现自己的胜率下降了,但又不知道为什么。现在,Cirno想知道在给定自己和Marisa所选的字符串时,自己获胜的概率。

    输入
    第一行为T,表示输入数据组数。
    下面T组数据。每组数据都是两个空格分割的,长度均为n的,由HT组成的字符串。

    输出
    对第i组数据,输出
    Case #i:
    然后输出Cirno获胜的概率,并以最简分数形式输出。

    限制条件
    1<=T<=500
    1<=n<=9+9+9

    样例输入
    3
    H T
    HT TH
    HH TH

    样例输出
    Case #1:
    1/2
    Case #2:
    1/2
    Case #3:
    1/4

    解题报告:

    # input1/output1: n <=3
    方法比较多,可以用和input2/outpu2类似的方法,以2^n为状态。
    也可以用Monte Carlo求出浮点数解,反过来得到精确解(可以假设分母都不会太大)。
    还可以利用对称性分类,再人肉求解后打表(有不少是1/2)。

    # input2/output2: n <= 27
    以输入的字符串a和b的所有后缀作为状态,每抛一次硬币,就有一半的概率转移到两个新的状态。
    状态a和b本身是终止状态,对应的胜率分别为1和2。
    p_a = 1
    p_b = 0
    而对于其余状态i,则有
    p_i = 0.5 * p_{s(i+H)} + 0.5 * p_{s(i+T)}
    于是可以得到一个n元线性方程组,用Gauss消元法可解。

    # input3/output3: n <= 729
    算法参考solution3.rb。
    记k_{ij}=correlation(i, j), k_i=k_{ii}-k_{ij}
    a胜利的概率是k_b/(k_a+k_b)
    b胜利的概率是k_a/(k_a+k_b)

    参考:String overlaps, pattern matching, and nontransitive games。

    解题代码:


    #include <cstdio>
    #include <string>
    #include <vector>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    typedef long long llint;
    
    llint gcd(llint a, llint b) {
      return b == 0 ? a : gcd(b, a % b);
    }
    
    struct Fraction {
      llint num, den;
    
      Fraction(llint n = 0, llint d = 1): num(n), den(d) {
        llint g = gcd(num, den);
        num /= g;
        den /= g;
        if (den < 0) {
          num = -num;
          den = -den;
        }
      }
    };
    
    Fraction operator+(const Fraction& lhs, const Fraction& rhs) {
      llint g = gcd(lhs.den, rhs.den);
      return Fraction(lhs.num * (rhs.den / g) + rhs.num * (lhs.den / g), lhs.den / g * rhs.den);
    }
    
    Fraction operator-(const Fraction& lhs, const Fraction& rhs) {
      return lhs + Fraction(-rhs.num, rhs.den);
    }
    
    Fraction operator*(const Fraction& lhs, const Fraction& rhs) {
      llint g1 = gcd(lhs.num, rhs.den);
      llint g2 = gcd(rhs.num, lhs.den);
      return Fraction((lhs.num / g1) * (rhs.num / g2), (lhs.den / g2) * (rhs.den / g1));
    }
    
    Fraction operator/(const Fraction& lhs, const Fraction& rhs) {
      return lhs * Fraction(rhs.den, rhs.num);
    }
    
    Fraction operator==(const Fraction& lhs, const Fraction& rhs) {
      return lhs.num == rhs.num && lhs.den == rhs.den;
    }
    
    
    const int MAXN = 64;
    
    void LU(int n, Fraction a[MAXN][MAXN], int r[MAXN], int c[MAXN]) {
      for (int i = 0; i < n; ++i) {
        r[i] = c[i] = i;
      }
      for (int k = 0; k < n; ++k) {
        int ii = -1, jj = -1;
        for (int i = k; ii == -1 && i < n; ++i) {
          for (int j = k; jj == -1 && j < n; ++j) {
            if (a[i][j].num != 0) {
              ii = i;
              jj = j;
            }
          }
        }
        swap(r[k], r[ii]);
        swap(c[k], c[jj]);
        for (int i = 0; i < n; ++i) {
          swap(a[i][k], a[i][jj]);
        }
        for (int j = 0; j < n; ++j) {
          swap(a[k][j], a[ii][j]);
        }
        for (int i = k + 1; i < n; ++i) {
          a[i][k] = a[i][k] / a[k][k];
          for (int j = k + 1; j < n; ++j) {
            a[i][j] = a[i][j] - a[i][k] * a[k][j];
          }
        }
      }
    }
    
    void solve(int n, Fraction a[MAXN][MAXN], int r[MAXN], int c[MAXN], Fraction b[MAXN]) {
      static Fraction x[MAXN];
      for (int i = 0; i < n; ++i) {
        x[i] = b[r[i]];
      }
      for (int i = 0; i < n; ++i) {
        for (int j = 0; j < i; ++j) {
          x[i] = x[i] - a[i][j] * x[j];
        }
      }
      for (int i = n - 1; i >= 0; --i) {
        for (int j = n - 1; j > i; --j) {
          x[i] = x[i] - a[i][j] * x[j];
        }
        x[i] = x[i] / a[i][i];
      }
      for (int i = 0; i < n; ++i) {
        b[c[i]] = x[i];
      }
    }
    
    Fraction a[MAXN][MAXN];
    int r[MAXN];
    int c[MAXN];
    Fraction b[MAXN];
    
    int main() {
      int n, m;
      string x, y, z;
      vector<string> v;
    
      int TT, NN;
      cin >> NN;
      for (TT = 1; TT <= NN; TT++) {
        cin >> x >> y;
        v.clear();
        n = x.length();
        for (int i = 0; i <= n; ++i) {
          v.push_back(x.substr(0, i));
          v.push_back(y.substr(0, i));
        }
        sort(v.begin(), v.end());
        v.erase(unique(v.begin(), v.end()), v.end());
        m = v.size();
    
        for (int i = 0; i < m; ++i) {
          fill(a[i], a[i] + m, 0);
          a[i][i] = 1;
          b[i] = v[i] == x ? 1 : 0;
          if (v[i] == x || v[i] == y) {
            continue;
          }
          const char char_list[2] = {'H', 'T'};
          for (int list_idx = 0; list_idx < 2; list_idx ++) {
            char c = char_list[list_idx];
            //for (char c: {'H', 'T'}) {
            z = v[i] + c;
            while (find(v.begin(), v.end(), z) == v.end()) {
              z = z.substr(1);
            }
            int j = find(v.begin(), v.end(), z) - v.begin();
            a[i][j] = a[i][j] - Fraction(1, 2);
          }
        }
    
        LU(m, a, r, c);
        solve(m, a, r, c, b);
    cout<<"Case #"<<TT<<":"<<endl;
    cout<<b[0].num<<"/"<<b[0].den<<endl;
    
    //    printf("Case #%d:
    ", TT);
    //    printf("%lld/%lld
    ", b[0].num, b[0].den);
      }
    
      return 0;
    }

  • 相关阅读:
    20165101刘天野 2017-2018-2 《Java程序设计》 结对编程练习_四则运算(第一周)
    20165101刘天野 2017-2018-2 《Java程序设计》第6周学习总结
    20165101 实验一 Java开发环境的熟悉
    20165101刘天野 2017-2018-2 《Java程序设计》第5周学习总结
    HTML——meta
    CSS——改变浏览器滚动条样式
    HTML5——移动端的点击、拖拽
    JS高级——弹出框的美化
    JS高级——监听浏览器的返回事件
    JS高级——文件操作
  • 原文地址:https://www.cnblogs.com/hosealeo/p/4190489.html
Copyright © 2011-2022 走看看