【问题描述】
Alice打算从自动取款机上取出她的所有存款。但是她忘了自己有多少存款了,她只知道存款不超过k块钱。 但是这台取款机很奇怪,它不支持余额查询功能,Alice只能通过多次尝试的方式取钱。每次尝试,Alice输入一个提取金额y,若账户余额>=y,取款机会立即吐出y块钱。若余额<y,取款机会发出警告。如果取款机发出了w次警告,它会认为Alice在故意捣乱,就会立即把卡吞掉。
请你帮忙计算,在不被吞卡的情况下,期望多少次就能取出所有的钱?
【输入格式】
有5组数据
对于每组数据,只有一行, 两个整数 k和w.
【输出格式】
五行,每行对应一组数据的结果,只有一个数字,表示问题的答案,保留6个小数位。
【数据范围】
对于100%的数据, 1≤K,W≤2000
这真是一个神级取款机
题解
对于可能剩余 元钱,
次错误的状态,取钱
的范围是
,共有
种可能
而取 元钱无非就两种结果:
①取到了 那么剩下的可能的钱就是
,而剩余错误的次数仍然为
也就是说
②没取到 剩下的可能钱数就可能为
(因为
一定存在不合法的取钱情况),错误次数也就变成了
也就是
所以说我们枚举合法剩余金钱
那么合法的取钱的情况就是取 元钱,概率是
反之则是选择取 ,概率是
也就是说
这是一个反向的递推,+1就是表示每一步往后推都要走一步,取 是为了选择最优策略
有一个细节就是,对于每一次选择,我们即使是使用二分的策略,也能保证错误的次数在 级别,所以错误的次数上线就是
附上超级短的代码
#include <iostream>
#include <cstdio>
using namespace std;
double dp[2345][17];
void DP()
{
for(int i=1;i<=2000;i++)
for(int j=0;j<=16;j++)dp[i][j]=10000;
for(int i=1;i<=16;i++)dp[0][i]=0;
for(int i=1;i<=2000;i++)
for(int t=1;t<=16;t++)
for(int j=1;j<=i;j++)
dp[i][t]=min(dp[i][t],dp[i-j][t]*(i-j+1)/(i+1)+dp[j-1][t-1]*j/(i+1)+1);
}
int main()
{
freopen("atm.in","r",stdin);
freopen("atm.out","w",stdout);
int T=5,m,t;
DP();
while(T--)
{
scanf("%d%d",&m,&t);
t=min(t,15);
printf("%.6lf\n",dp[m][t]);
}
}