【题解】JLOI2013卡牌游戏

  这题最开始是用 \(n^{4}\)的算法水过的,之后才想出的\(n^{3}\)正解。首先,\(n^{4}\) 应该是很容易想到的:设状态 \(f[i][j][k]\) 为有 \(i\) 个人,庄家为 \(j\) 号人时,第 \(k\) 个人胜出的概率。这样,只需要去掉本轮淘汰的人,加上 \(i - 1\) 个人时该人胜出的概率即可。

#include <bits/stdc++.h>
using namespace std;
#define maxn 55
#define db double
int n, m, a[maxn];
db P, f[maxn][maxn][maxn];

int read()
{
    int x = 0, k = 1;
    char c;
    c = getchar();
    while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * k;
}

int main()
{
    n = read(), m = read();
    P = (db) 1 / (db) m;
    for(int i = 1; i <= m; i ++) a[i] = read();
    f[1][1][1] = 1;
    for(int i = 2; i <= n; i ++)
        for(int j = 1; j <= i; j ++)
            for(int k = 1; k <= i; k ++)
            {
                for(int x = 1; x <= m; x ++)
                {
                    int t = (a[x] + j - 1) % i, T = t + 1, K = k; 
                    if(!t) t = i; 
                    if(t == k) continue;
                    if(K > t) K -= 1; if(T > t) T -= 1;
                    f[i][j][k] += P * f[i - 1][T][K];
                }
            }
    for(int i = 1; i <= n; i ++)
        printf("%.2lf%% ", f[n][1][i] * 100);
    return 0;
}

   但是这题还有更优的做法。我们再看一看自己所设置的状态,详加思考就会发现:其实第二维是不必要的。谁做庄家实际上都是一个相对的概念,我们可以强制让\(1\) 号为庄家,这样只需要在新的环上找出原来编号为 \(k\) 的人对应的新编号 \(k'\) 并加上其概率就好啦。

#include <bits/stdc++.h>
using namespace std;
#define maxn 55
#define db double
int n, m, a[maxn];
db P, f[maxn][maxn];

int read()
{
    int x = 0, k = 1;
    char c;
    c = getchar();
    while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * k;
}

int main()
{
    n = read(), m = read();
    P = (db) 1 / (db) m;
    for(int i = 1; i <= m; i ++) a[i] = read();
    f[1][1] = 1;
    for(int i = 2; i <= n; i ++)
        for(int k = 1; k <= i; k ++)
            for(int x = 1; x <= m; x ++)
            {
                int t = a[x] % i, T = t + 1, K = k; 
                if(!t) t = i; 
                if(t == k) continue;
                if(K > t) K -= 1; if(T > t) T -= 1;
                if(K < T) K = (i - T + K);
                else if(K > T) K = K - T + 1;
                else K = 1;
                f[i][k] += P * f[i - 1][K];
            }
    for(int i = 1; i <= n; i ++)
        printf("%.2lf%% ", f[n][i] * 100);
    return 0;
}

 

posted @ 2018-05-25 21:27  Twilight_Sx  阅读(254)  评论(0编辑  收藏  举报