图灵杯-第四届“图灵杯”NEUQ-ACM 程序设计竞赛-A-谷神的赌博游戏

来源:互联网 发布:外国法制史 知乎 编辑:程序博客网 时间:2024/05/16 06:20

ACM模版

描述

描述

题解

这个题是一个数论题,主要是推公式,但是 dp 同样是可以过的……

先来说 dp(代码 One),设置 dp[i][j][k][r] 表示 %3 后的数 1 出现了 i 次,2 出现了 j 次,0 出现了 k 次,此时余数为 r 的概率,这样我们就可以轻松转移出来每一个状态了,具体状态转移看代码吧!

说到数论,这个题首先我们可以将所有数 %3 后发现,02 都出现了 n 次,1 出现了 n+1 次,这里 0 对序列的余数状态无影响,所以我们最后考虑。
此时存在两种情况,以 1 打头、2 打头,分别考虑下来,
第一种的序列是 11212121212,这种情况,很明显,从头到尾都是唯一的,并且是合法的,这里的唯一说的是 %3 后的结果,酱紫,我们知道了每个数所能放的位置,所以只考虑 12 的计算结果为 n!(n+1)!,接着我们可以考虑往其中插入 0,由于开头不能插,所以插零的方案数为 (2n+1)(2n+2)3n,根据乘法原理,得到以 1 打头的情况数为:n!(n+1)!(2n+1)(2n+2)3n
第二种的序列是 22121212111,这种情况,我们会发现,当 2 使用完后,会紧接着放 111,而这里从第二个开始,就不合法了,所以以 2 打头的情况是无解的。

而所有的排列结果为 (3n+1)!,所以相除化简后:

n!(n+2)2n(3n+1)

化简形式不唯一,考虑到代码的最简,化成下边的形式最好:
n!(n+1)(n+1)2n(3n+1)

就酱,这个题算是告一段落了~~~

代码

One:

#include <iostream>#include <cstring>using namespace std;const int MAXN = 22;int n;double dp[MAXN][MAXN][MAXN][3];int main(){    int T;    cin >> T;    while (T--)    {        memset(dp, 0, sizeof(dp));        cin >> n;        int m = 3 * n + 1;        for (int i = 0; i <= n + 1; i++)        {            for (int j = 0; j <= n; j++)            {                for (int k = 0; k <= n; k++)                {                    if (i + j + k == 1)                    {                        if (i)                        {                            dp[i][j][k][1] = (n + 1) * 1.0 / m;                        }                        else if (j)                        {                            dp[i][j][k][2] = n * 1.0 / m;                        }                        continue;                    }                    int now = m - i - j - k + 1;                    dp[i][j][k][1] = (j == 0 ? 0 : dp[i][j - 1][k][2] * (n - j + 1) / now)                                   + (k == 0 ? 0 : dp[i][j][k - 1][1] * (n - k + 1) / now);                    dp[i][j][k][2] = (i == 0 ? 0 : dp[i - 1][j][k][1] * (n - i + 2) / now)                                   + (k == 0 ? 0 : dp[i][j][k - 1][2] * (n - k + 1) / now);                }            }        }        printf("%.9lf\n", dp[n + 1][n][n][1]);    }    return 0;}

Two:

#include <cstdio>int n;double ans;int main(){    int T;    scanf("%d", &T);    while (T--)    {        scanf("%d", &n);        ans = (n + 1.0) / (3 * n + 1);        for (int i = 1; i <= n; i++)        {            ans = ans * i / (i + n);        }        printf("%.9f\n", ans);    }    return 0;}
阅读全文
0 0