zoukankan      html  css  js  c++  java
  • [YNOI2019]游戏

    题目

      (原题题意不清)有(n)个人玩,开始时从(1)号到(n)依次排队。每轮游戏有(4)人参加,一轮游戏中每位玩家胜率相等,胜者将称为擂主继续游戏,剩下三位将按照入场顺序排在队尾,接下来按队列继续游戏。如果擂主在本轮输了,将排在剩下两名输了的选手的前面。获得最终胜利的条件为连胜(m)。最后询问第(k)个人获得最终胜利的概率。(4leqslant nleqslant10)(kleqslant n)(mleqslant 10)

    题解

      难在状态设计。状态也许依赖于顺序,但仔细想一想可以发现我们只关心第(k)个人的位置以及擂主的连胜数(不管他是谁)。于是可以得到状态(f_{i,j})表示第(k)个人在从前往后的第(j)个位置,当前擂主(站在第一位的)连胜(i)场时第(k)个人能获得最终胜利的概率。显然(f_{m,1}=1)(f_{m,i}=0(i e1))。接着我们分类讨论:

    (k)个人是擂主,即(j=1)

      那么守擂成功的概率为(25\%),失败的概率为(75\%),分别对应到状态(f_{i+1,1})(f_{1,n-2})(在另外两人之前),即

    [f_{i+1,1}leftarrow f_{i,1} imes25\% ]

    [f_{1,n-2}leftarrowsum_{i=0}^{m-1}f_{i,1} imes75\% ]

    其他人是擂主,即(j e1)

      稍微复杂了些。分为(k)在前四个人中以及(k)不在前四个人中。然后还要细分。

      当(j=2,3,4)时,第(k)个人均有(25\%)的概率获胜,此时会转移到(f_{1,1}),即

    [f_{1,1}leftarrow 25\% imessum_{i=0}^{m-1}f_{i,2}+f_{i,3}+f_{i,4} ]

      对于剩下的(75\%)(j)一定会跑到队尾,具体在哪里仍然要细分。

      当(j=2)时,仍然要考虑擂主会不会获胜。仍然有(25\%)的概率擂主会获胜,此时第(k)个人会到第(n-2)个位置,即到达(f_{i+1,n-2});如果擂主失败,那么对于(k)获胜的情况上面讨论过,剩下(50\%)另外两人获胜,擂主连胜次数变成(1),但注意此时(k)会跑到(n-1)的位置因为擂主要排在他前面,即转移成(f_{1,n-1}),即

    [f_{i+1,n-2}leftarrow25\% imes f_{i,2} ]

    [f_{1,n-1}leftarrow50\% imessum_{i=0}^{m-1}f_{i,2} ]

      当(j=3)时,同上,如果擂主连胜,有(25\%)的概率转移到(f_{i+1,n-1});如果其它两人获胜,要细分是(k)前面的人还是后面的人(因为这会影响到队列顺序)。如果前面的人赢了,(k)号会排到(n-1)位,即(25\%)的概率转移到(f_{1,n-1});如果后面的人赢了,(k)会排到(n)位,即(25\%)的概率转移到(f_{1,n}),即

    [f_{i+1,n-1}leftarrow25\% imes f_{i,3} ]

    [f_{1,n-1}leftarrow25\% imessum_{i=0}^{m-1}f_{i,3} ]

    [f_{1,n}leftarrow25\% imessum_{i=0}^{m-1}f_{i,3} ]

      当(j=4)时,继续分析,得到下面

    [f_{i+1,n}leftarrow25\% imes f_{i,4} ]

    [f_{1,n}leftarrow50\% imessum_{i=0}^{m-1}f_{i,4} ]

      其余情况下,第(k)个人只会前进(3)位,分为两种情况

    [f_{i+1, j-3}leftarrow25\% imes f_{i,j} ]

    [f_{1,j-3}leftarrow75\% imes f_{i,j} ]

      最后根据以上的关系式列方程,gauss消元即可,最终答案为(f_{0,k})。状态集(mathcal O(nm)),复杂度(mathcal O(n^3m^3))

      听说还有(mathcal O(n^2m+n^3))的复杂度?这里( ext{%%%C}color{red}{ ext{razysky}})。发现所有转移都是要么往连胜次数(i+1)要么往(1),构成环的关键是从(f_{i,j})跳到了(f_{1,j})。这里把所有的(f_{1,x})看成未知数,然后一级一级往上列出(f_{i,j})(f_{1,x})的关系,回到(f_{1,x})的恰好能列出来方程,最后能得到(mathcal O(nm))个方程,右边是(f_{1,x}),左边是(sum f_{1,i})。把右边相同的合并起来,最后合并成(n)个方程,再进行gauss消元,就能做到这个复杂度了。

    代码

      直接gauss消元的做法。

    #include <bits/stdc++.h>
    
    #define rep(i, a, b) for (int i = a, i##end = b; i <= i##end; ++i)
    #define per(i, a, b) for (int i = a, i##end = b; i >= i##end; --i)
    #define rep0(i, a) for (int i = 0, i##end = a; i < i##end; ++i)
    #define per0(i, a) for (int i = a-1; ~i; --i)
    
    const int maxn = 15;
    
    int n, m, k;
    double a[maxn*maxn][maxn*maxn];
    
    void Gauss(int n) {
        rep(i, 1, n) {
            int r = i;
            rep(j, i+1, n) if (fabs(a[j][i]) > fabs(a[r][i])) r = j;
            if (r != i) rep(j, 1, n+1) std::swap(a[r][j], a[i][j]);
            rep(j, 1, n) if (j != i) {
                double t = a[j][i] / a[i][i];
                rep(k, 1, n+1) a[j][k] -= t * a[i][k];
            }
        }
        rep(i, 1, n) a[i][n+1] /= a[i][i];
    }
    
    #define id(i, j) ((i)*n+(j))
    
    int main() {
        for (int T = read(); T; T--) {
            n = read(), m = read(), k = read();
            memset(a, 0, sizeof a);
            rep(i, 0, m)
                rep(j, 1, n)
                    a[id(i, j)][id(i, j)] = 1;
            a[id(m, 1)][n*(m+1)+1] = 1;
            rep0(i, m) {
                a[id(i, 1)][id(i+1, 1)] -= 0.25;
                a[id(i, 1)][id(1, n-2)] -= 0.75;
                a[id(i, 2)][id(1, 1)] -= 0.25;
                a[id(i, 3)][id(1, 1)] -= 0.25;
                a[id(i, 4)][id(1, 1)] -= 0.25;
                a[id(i, 2)][id(i+1, n-2)] -= 0.25;
                a[id(i, 2)][id(1, n-1)] -= 0.5;
                a[id(i, 3)][id(i+1, n-1)] -= 0.25;
                a[id(i, 3)][id(1, n-1)] -= 0.25;
                a[id(i, 3)][id(1, n)] -= 0.25;
                a[id(i, 4)][id(i+1, n)] -= 0.25;
                a[id(i, 4)][id(1, n)] -= 0.5;
                rep(j, 5, n)
                    a[id(i, j)][id(i+1, j-3)] -= 0.25,
                    a[id(i, j)][id(1, j-3)] -= 0.75;
            }
            Gauss(n*(m+1));
            printf("%.6lf
    ", a[id(0, k)][n*(m+1)+1]);
        }
        return 0;
    }
    
  • 相关阅读:
    20155339 Exp9 Web安全基础
    20155339 Exp8 Web基础
    20155339 Exp7 网络欺诈防范
    20155339 Exp6 信息搜集与漏洞扫描
    20155339 Exp5 MSF基础应用
    20155339 Exp4 恶意代码分析
    20155339 Exp3 免杀原理与实践
    20155339平措卓玛 Exp2 后门原理与实践
    20155339平措卓玛 Exp1 PC平台逆向破解(5)M
    20155339 第16周课堂实践加分作业
  • 原文地址:https://www.cnblogs.com/ac-evil/p/12544492.html
Copyright © 2011-2022 走看看