题目描述
Alice\texttt{Alice}Alice 和 Bob\texttt{Bob}Bob 设计了一个双人猜数游戏。游戏开始前,他们约定两个正整数:范围 NNN 和 允许的失误次数上限 SSS。Alice\texttt{Alice}Alice 秘密选择一个整数 XXX(0≤X<N0 \le X < N0≤X<N),然后 Bob\texttt{Bob}Bob 轮流猜测整数。对于 Bob\texttt{Bob}Bob 的每次猜测,Alice\texttt{Alice}Alice 会给出以下三种回应之一:
- strike\texttt{strike}strike:如果猜测的数字大于 XXX;
- smile\texttt{smile}smile:如果猜测的数字小于 XXX;
- stop\texttt{stop}stop:如果猜测的数字等于 XXX(此时游戏结束,Bob\texttt{Bob}Bob 获胜)。
如果 Bob\texttt{Bob}Bob 累计收到 SSS 次 strike\texttt{strike}strike,则游戏结束,Alice\texttt{Alice}Alice 获胜。
Bob\texttt{Bob}Bob 希望在正式比赛前进行训练。他需要知道,对于给定的 NNN 和 SSS,在最坏情况下,他需要多少次猜测才能确保猜中 Alice\texttt{Alice}Alice 选择的任意数字 XXX,并且在此过程中他最多收到 S−1S-1S−1 次 strike\texttt{strike}strike(否则他会输掉游戏)。
输入格式:第一行包含一个整数 CCC,表示测试用例的数量。接下来 CCC 行,每行包含两个整数 NNN 和 SSS,分别表示数字范围和允许的 strike\texttt{strike}strike 次数上限。保证 1≤N≤10001 \le N \le 10001≤N≤1000,1≤S≤201 \le S \le 201≤S≤20。
输出格式:对于每个测试用例,输出一行一个整数,表示 Bob\texttt{Bob}Bob 在最坏情况下所需的最少猜测次数。
题目分析
这是一个典型的最坏情况下的最优策略问题,类似于带有限制的二分搜索。我们可以从以下几个关键点理解题目:
- 游戏目标:Bob\texttt{Bob}Bob 需要保证无论 Alice\texttt{Alice}Alice 选择哪个数字 XXX,他都能在收到少于 SSS 次 strike\texttt{strike}strike 的情况下猜中。
- 策略限制:每次猜测如果得到 strike\texttt{strike}strike,会消耗一次“允许的失误机会”;如果得到 smile\texttt{smile}smile,则不消耗。
- 最坏情况:我们需要考虑在所有可能的 XXX 下,Bob\texttt{Bob}Bob 所需猜测次数的最大值,并最小化这个最大值。
解题思路
1. 问题建模
设 dp[n][s]dp[n][s]dp[n][s] 表示当数字范围为 [0,n−1][0, n-1][0,n−1](即共有 nnn 个可能的数字),且 Bob\texttt{Bob}Bob 最多还能承受 sss 次 strike\texttt{strike}strike 时,在最坏情况下需要的最少猜测次数。
初始条件:
- 如果没有数字需要猜(n=0n = 0n=0),则不需要猜测:dp[0][s]=0dp[0][s] = 0dp[0][s]=0。
- 如果不能承受任何 strike\texttt{strike}strike(s=0s = 0s=0),那么 Bob\texttt{Bob}Bob 只能从最小的数字开始逐个猜测,最坏情况需要猜 nnn 次(当 X=n−1X = n-1X=n−1 时):dp[n][0]=ndp[n][0] = ndp[n][0]=n。
状态转移:
假设当前范围大小为 nnn,我们选择猜测位置 kkk(0≤k<n0 \le k < n0≤k<n)。猜测后有三种可能:
- 猜中:游戏结束,本次猜测计数为 111。
- 得到 strike\texttt{strike}strike(猜大了):说明 X<kX < kX<k,剩余范围大小为 kkk,剩余可承受 strike\texttt{strike}strike 次数为 s−1s-1s−1,后续需要的最少猜测次数为 dp[k][s−1]dp[k][s-1]dp[k][s−1]。
- 得到 smile\texttt{smile}smile(猜小了):说明 X>kX > kX>k,剩余范围大小为 n−k−1n-k-1n−k−1,剩余可承受 strike\texttt{strike}strike 次数仍为 sss,后续需要的最少猜测次数为 dp[n−k−1][s]dp[n-k-1][s]dp[n−k−1][s]。
由于我们要保证最坏情况,所以对于固定的 kkk,需要的猜测次数为:
guesses(k)=1+max(dp[k][s−1], dp[n−k−1][s])
\texttt{guesses}(k) = 1 + \max(dp[k][s-1],\ dp[n-k-1][s])
guesses(k)=1+max(dp[k][s−1], dp[n−k−1][s])
其中 111 表示当前这次猜测。
为了最小化最坏情况,我们选择最优的 kkk:
dp[n][s]=mink=0n−1(1+max(dp[k][s−1], dp[n−k−1][s]))
dp[n][s] = \min_{k=0}^{n-1} \left(1 + \max(dp[k][s-1],\ dp[n-k-1][s])\right)
dp[n][s]=k=0minn−1(1+max(dp[k][s−1], dp[n−k−1][s]))
2. 算法实现
由于 N≤1000N \le 1000N≤1000,S≤20S \le 20S≤20,我们可以使用动态规划预先计算所有可能的 dp[n][s]dp[n][s]dp[n][s] 值。对于每个测试用例,直接查表输出结果即可。
- 时间复杂度:O(N2⋅S)O(N^2 \cdot S)O(N2⋅S),对于给定范围是可接受的。
- 空间复杂度:O(N⋅S)O(N \cdot S)O(N⋅S)。
3. 注意事项
- 题目中给出的 SSS 是 Alice\texttt{Alice}Alice 获胜所需的 strike\texttt{strike}strike 次数,因此 Bob\texttt{Bob}Bob 最多能承受 S−1S-1S−1 次 strike\texttt{strike}strike。我们在计算时实际使用的 s=S−1s = S-1s=S−1。
- 当 S=1S = 1S=1 时,Bob\texttt{Bob}Bob 不能承受任何 strike\texttt{strike}strike(s=0s=0s=0),此时只能顺序猜测,需要 NNN 次。
代码实现
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1005;
const int MAX_S = 25;
const int INF = 0x3f3f3f3f;
int dp[MAX_N][MAX_S];
// 预处理所有 dp[n][s] 的值
void precompute() {
// 初始化:没有数字需要猜的情况
for (int s = 0; s < MAX_S; ++s) dp[0][s] = 0;
// 初始化:不能承受任何 strike 的情况
for (int n = 1; n < MAX_N; ++n) dp[n][0] = n;
// 动态规划递推
for (int n = 1; n < MAX_N; ++n) {
for (int s = 1; s < MAX_S; ++s) {
int best = INF;
// 尝试所有可能的猜测位置 k
for (int k = 0; k < n; ++k) {
int strikePart = dp[k][s - 1]; // 猜大后的情况
int smilePart = dp[n - k - 1][s]; // 猜小后的情况
int worst = 1 + max(strikePart, smilePart);
if (worst < best) best = worst;
}
dp[n][s] = best;
}
}
}
int main() {
precompute(); // 预先计算
int c, n, S;
cin >> c;
while (c--) {
cin >> n >> S;
int s = S - 1; // Bob 最多能承受的 strike 次数
if (s < 0) s = 0; // 安全处理边界
cout << dp[n][s] << endl;
}
return 0;
}
样例解析
样例输入
2
3 2
4 1
样例输出
2
4
解释:
-
N=3, S=2N=3,\ S=2N=3, S=2:Bob\texttt{Bob}Bob 最多能承受 111 次 strike\texttt{strike}strike。最优策略是先猜 111:
- 若得 strike\texttt{strike}strike,则 X=0X=0X=0,下一轮猜 000,共 222 次。
- 若得 smile\texttt{smile}smile,则 X=2X=2X=2,下一轮猜 222,共 222 次。
- 若猜中,则只需 111 次。
最坏情况为 222 次。
-
N=4, S=1N=4,\ S=1N=4, S=1:Bob\texttt{Bob}Bob 不能承受任何 strike\texttt{strike}strike(s=0s=0s=0)。只能从 000 开始顺序猜测,最坏情况(X=3X=3X=3)需要猜 0,1,2,30,1,2,30,1,2,3 共 444 次。
总结
本题通过动态规划巧妙地处理了带有 strike\texttt{strike}strike 限制的猜数策略问题。关键在于定义状态 dp[n][s]dp[n][s]dp[n][s] 并找到正确的状态转移方程,即每次猜测后根据反馈(strike\texttt{strike}strike 或 smile\texttt{smile}smile)进入不同的子问题。预处理所有状态后,即可快速回答每个测试用例。该算法在给定数据范围内效率良好,是解决此类“最坏情况最优策略”问题的典型方法。
585

被折叠的 条评论
为什么被折叠?



