描述
题解
这个题是一个数论题,主要是推公式,但是 dp 同样是可以过的……
先来说 dp(代码 One),设置
dp[i][j][k][r]
表示
%3
后的数
1
出现了
说到数论,这个题首先我们可以将所有数
%3
后发现,
0
和
此时存在两种情况,以
1
打头、
第一种的序列是
1121212…1212
,这种情况,很明显,从头到尾都是唯一的,并且是合法的,这里的唯一说的是
%3
后的结果,酱紫,我们知道了每个数所能放的位置,所以只考虑
1
和
第二种的序列是
2212121…2111
,这种情况,我们会发现,当
2
使用完后,会紧接着放
而所有的排列结果为
化简形式不唯一,考虑到代码的最简,化成下边的形式最好:
就酱,这个题算是告一段落了~~~
代码
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;
}