1 条题解
-
0
题意
有 种花色,每种花色有 张牌(点数 到 )。
皇家同花顺: 且花色相同。
初始随机抽 张牌,之后每轮:- 若手牌有皇家同花顺,获胜;
- 若牌堆空,失败;
- 否则,可弃掉任意手牌,然后抽牌至手牌 张或牌堆空。
求最小期望获胜轮数(获胜那轮不计入)。
关键转化
- 只有 这 张关键牌对获胜有用,其余牌无用。
- 每轮我们可以弃掉无用牌,所以手牌中永远只保留关键牌(且不会保留重复的关键牌,因为弃掉后抽新的)。
- 因此,游戏等价于:从 张牌中(包含 张关键牌和 张无用牌)每次抽一张,如果抽到未集齐的关键牌则保留,否则丢弃。当集齐某花色的全部 张关键牌时获胜。求期望抽牌次数。
状态表示
总关键牌数 。
用一个 位的二进制掩码 表示已收集的关键牌集合。
位 ()对应第 种花色的第 张关键牌(点数顺序固定为 )。
定义 为当前已收集 时,还需多少步才能获胜的期望。
边界条件
如果 包含某花色的全部 张关键牌,即存在 使得 在 这些位上全为 ,则已获胜:
转移方程
设:
- :已收集的关键牌数量
- :剩余牌数(已抽走的 张关键牌已移除,其余牌还在)
- :未收集的关键牌数量
下一张抽牌:
- 抽到未收集关键牌的概率
- 抽到已收集关键牌或无用牌的概率
设 $E_{next} = \frac{1}{\text{missing}} \sum_{i \notin mask} dp[mask \cup \{i\}]$ 为抽到未收集关键牌时的期望后继值。
由全期望公式:
$$dp[mask] = 1 + p \cdot E_{next} + (1-p) \cdot dp[mask] $$移项:
由于 ,所以:
算法步骤
. 初始化所有 ,。 . 递归计算 :
- 若 包含某花色的 张牌,返回 。
- 计算 ,,。
- 计算 $E_{next} = \frac{1}{\text{missing}} \sum_{i \notin mask} dp[mask \cup \{i\}]$。
- 返回 。 . 答案 。
复杂度
状态数 , 时最大 ,可接受。
每个状态遍历 个后继,总复杂度 。
完整代码
#include <bits/stdc++.h> using namespace std; int n; double dp[1 << 20]; bool vis[1 << 20]; bool hasRoyal(int mask) { for (int suit = 0; suit < n; suit++) { int royalMask = 0; for (int rank = 0; rank < 5; rank++) { royalMask |= (1 << (suit * 5 + rank)); } if ((mask & royalMask) == royalMask) return true; } return false; } double dfs(int mask) { if (vis[mask]) return dp[mask]; vis[mask] = true; if (hasRoyal(mask)) return dp[mask] = 0; int cnt = __builtin_popcount(mask); int total = 13 * n; int remain = total - cnt; int missing = 5 * n - cnt; double sumNext = 0; for (int i = 0; i < 5 * n; i++) { if (!(mask >> i & 1)) { sumNext += dfs(mask | (1 << i)); } } double E_next = sumNext / missing; dp[mask] = (double)remain / missing + E_next; return dp[mask]; } int main() { cin >> n; double ans = dfs(0); cout << fixed << setprecision(9) << ans << endl; return 0; }
示例验证
输入 ,输出约
输入 ,输出约
与题目样例一致。
总结
- 问题简化为收集特定 张关键牌,且必须集齐同一花色的 张。
- 用状态压缩 计算期望步数。
- 转移公式:$dp[mask] = \frac{\text{剩余牌数}}{\text{未收集关键牌数}} + \text{后继期望的平均}$。
- 1
信息
- ID
- 7188
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 1
- 标签
- 递交数
- 3
- 已通过
- 1
- 上传者