-
题意
爱丽丝参与一个大致基于纸牌游戏 “21点” 规则的游戏,描述如下:
爱丽丝以 0 分开始,并在她的得分少于 K 分时抽取数字。 抽取时,她从 [1, W] 的范围中随机获得一个整数作为分数进行累计,其中 W 是整数。 每次抽取都是独立的,其结果具有相同的概率。
当爱丽丝获得不少于 K 分时,她就停止抽取数字。 爱丽丝的分数不超过 N 的概率是多少? -
状态
将K当成是可以使用的权限值。那么每抽取一个数字,权限值少一点,累积的分数多一点。
f ( k ) f(k) f(k)表示当爱丽丝以权限值为 k k k时,继续这场游戏获胜的概率(这个时候,累积分数为 K − k K-k K−k )。
那么我们的答案其实就是 f ( K ) f(K) f(K)。
-
状态转移方程
f ( k ) = 1 / w ∗ ( f ( k − 1 ) + f ( k − 2 ) + … … + f ( k − w ) ) f(k) = 1/w*(f(k-1)+f(k-2)+……+f(k-w)) f(k)=1/w∗(f(k−1)+f(k−2)+……+f(k−w))
其实就是全概率公式。 -
注意点
注意到,权限值会从 K K K一直减少到 0 0 0,也可能一下子转移到负数,相当于最后一次抽取一下子全用光了权限值(并且还不够)。
那么基本状态其实就是:
f ( K − N ) = f ( K − N + 1 ) = … … = … … f ( 0 ) = 0 f(K-N)=f(K-N+1)=……=……f(0)=0 f(K−N)=f(K−N+1)=……=……f(0)=0
注意 f ( K − N − 1 ) 、 f ( K − N − 2 ) 、 … … f(K-N-1)、f(K-N-2)、…… f(K−N−1)、f(K−N−2)、……等等概率都为0,因为这个时候相当于累积分数超过了 N N N。
由于负数不能作为数组下标,还要做一个线性映射。 -
优化
用一个前缀和优化是很明显的。
class Solution {
public:
double new21Game(int N, int K, int W) {
double f[20010] = {
0}, sf[20010] = {
0},v = 1.0/W;
// K-x-10000 <= N-10000; K - x' <= N-10000; x'>= K-N+10000;
// x+10000 <= 10000; x' <= 10000
// x <------> x+10000;
// f[x] = v*f[x-1]+v*f[x-2]+…………+v*f[x-W];
// f[x+10000] = v*( f[x-1+10000] + ……………… + f[x-W+10000] );
for(int x=id(K-N);x<=id(0);x++){
f[x] = 1;
sf[x] = sf[x-1] + f[x];
}
for(int x=id(1);x<=id(K);x++){
// f[x] = v*( sf[x-W,x-1] );
f[x] = v*(sf[x-1]-sf[x-W-1]);
sf[x] = sf[x-1] + f[x];
}
return f[id(K)];
}
int id(int x){
return x+10000;
}
};
- 另一种状态表示
- d p [ x ] dp[x] dp[x]表示累计得分为 x x x的情况下,获胜的概率;
- 基本状态: d p [ x ] = 1 ( K < = x < = m i n ( N , K − 1 + W ) ) dp[x]=1(K<=x<=min(N,K-1+W)) dp[x]=1(K<=x<=min(N,K−1+W))
- 转移方程: d p [ x ] = 1 / W ∗ ( d p [ x + 1 ] + d p [ x + 2 ] ) + … … + d p [ x + W ] dp[x]=1/W*(dp[x+1]+dp[x+2])+……+dp[x+W] dp[x]=1/W∗(dp[x+1]+dp[x+2])+……+dp[x+W]
- 目标值: d p [ 0 ] dp[0] dp[0],(因为一开始得分为0)
- 差分优化或者后缀和优化。