Solution -「GLR-R4」芒种
Rainybunny · · 题解
\mathscr{Description}
[Link](), 懒得概括题意.jpg
\mathscr{Solution}
Subtask 1
Subtask 2
Subtask 3
尝试归纳证明. 假设当
-
选择两张未知牌 (未知牌共
2n-m=n=m 张); -
选择一张已知牌 (已知牌共
m 张), 一张未知牌; -
选择两张已知牌.
对于第一种决策, 因为已知牌中
对于第二种决策, 类似的, 先手有
可见
于是, 先手选择了第三种决策! 第三种决策没有任何效果, 仅仅是 "摆烂" 地过掉自己回合, 轮到对方操作. 此时对方又面临这三种决策的选择, 他又会 "摆烂" 过掉自己的回合 ... 双方都无法让自己的期望得分高于对方, 那么此时双方都会同意和局! 两人得分
Subtask 4
Subtask 5 来讲正解啦. 在 subtask 3 的证明过程中, 我们已经自然地引入了 "先手得分是否低于后手" 的讨论. 进一步的, 由于双方得分之和一定是
-
先手选择一张已知牌, 一张未知牌, 此时要求
m\ge1 , 有转移:\begin{array}{ccl} f(n,m) & \overset{\max}{\longleftarrow} & \frac{1}{2n-m}(1+f(n-1,m-1))-\frac{m-1}{2n-m}(1+f(n-1,m-1))\\ & & -\frac{2n-2m}{2n-m}f(n,m+1). \end{array} -
先手选择两张未知牌, 此时要求
2n-m\ge2 , 有转移:\begin{array}{ccl} f(n,m) & \overset{\max}{\longleftarrow} & \frac{n-m}{\binom{2n-m}{2}}(1+f(n-1,m))-\frac{\binom{m}{2}}{\binom{2n-m}{2}}(2+f(n-2,m-2))\\ & & -\frac{m(2n-2m)}{\binom{2n-m}{2}}(1+f(n-1,m))-\frac{2(n-m)(n-m-1)}{\binom{2n-m}{2}}f(n,m+2). \end{array} -
先手选择两张已知牌, 此时要求
m\ge2 . 注意这里不是f(n,m)\overset{\max}{\longleftarrow}-f(n,m) , 如果这种决策是优秀的, 双方会直接和局, 所以有:\begin{array}{ccl} f(n,m) & \overset{\max}{\longleftarrow} & 0. \end{array}
边界为
\mathscr{Code}
/*+Rainybunny+*/
#include <bits/stdc++.h>
#define rep(i, l, r) for (int i = l, rep##i = r; i <= rep##i; ++i)
#define per(i, r, l) for (int i = r, per##i = l; i >= per##i; --i)
typedef double VType;
// typedef long double VType;
template <typename Tp>
inline void chkmin(Tp& u, const Tp& v) { v < u && (u = v, 0); }
template <typename Tp>
inline void chkmax(Tp& u, const Tp& v) { u < v && (u = v, 0); }
template <typename Tp>
inline Tp imin(const Tp& u, const Tp& v) { return u < v ? u : v; }
template <typename Tp>
inline Tp imax(const Tp& u, const Tp& v) { return u < v ? v : u; }
const int MAXN = 5e3;
bool vis[MAXN + 5][MAXN + 5];
VType f[MAXN + 5][MAXN + 5];
inline VType calc(const int n, const int m) {
if (n <= 0 || m < 0 || n < m) return 0;
VType& cur = f[n][m];
if (vis[n][m]) return cur;
vis[n][m] = true, cur = -1e100;
if (m >= 1) {
chkmax(cur, (1 + calc(n - 1, m - 1)
- (m - 1) * (1 + calc(n - 1, m - 1))
- 2 * (n - m) * calc(n, m + 1))
/ (2 * n - m));
}
if (2 * n - m > 1) {
chkmax(cur, 2 * ((n - m) * (1 + calc(n - 1, m))
- m * (m - 1) / 2 * (2 + calc(n - 2, m - 2))
- 2 * m * (n - m) * (1 + calc(n - 1, m))
- 2 * (n - m) * (n - m - 1) * calc(n, m + 2))
/ ((2 * n - m) * (2 * n - m - 1)));
}
if (m >= 2) chkmax(cur, 0.);
return cur;
}
int main() {
int T, n, m;
scanf("%d", &T);
while (T--) {
scanf("%d %d", &n, &m);
printf("%.12f\n", (n + calc(n, m)) / 2);
}
return 0;
}