1006 Bowcraft
题意:
商店提供多种升级书,每本升级书有 a A \frac aA Aa的概率升一级,如果升级失败,有 b B \frac bB Bb的概率使等级降为0。每购买一本书,会等概率的从 [ 0 , A − 1 ] [0,A-1] [0,A−1]中生成数字 a a a,从 [ 0 , B − 1 ] [0,B-1] [0,B−1]中生成数字 b b b。问在最优策略下升到 k k k级买书的期望数量。
分析:
考虑
d
p
dp
dp求解:
d
p
[
i
]
dp[i]
dp[i]表示从0级升到
i
i
i级的期望买书数量。
假设当前买的书的状态是
(
a
,
b
)
(a,b)
(a,b),则我们可以选择使用或者不使用:
令
α
=
a
A
,
β
=
b
B
\alpha=\frac aA, \beta=\frac bB
α=Aa,β=Bb
1.若使用这本书,则升到
i
+
1
i + 1
i+1级的期望是:
Y
=
d
p
[
i
+
1
]
=
d
p
[
i
]
+
1
+
(
1
−
α
)
∗
(
1
−
β
)
∗
(
d
p
[
i
+
1
]
−
d
p
[
i
]
)
+
(
1
−
α
)
∗
β
∗
d
p
[
i
+
1
]
)
Y=dp[i+1]=dp[i]+1+(1-\alpha)*(1-\beta)*(dp[i+1]-dp[i])+(1-\alpha)*\beta*dp[i+1])
Y=dp[i+1]=dp[i]+1+(1−α)∗(1−β)∗(dp[i+1]−dp[i])+(1−α)∗β∗dp[i+1])
解释一下: 我们成功升一级的期望是
d
p
[
i
]
+
1
dp[i]+1
dp[i]+1,因为要购买一本书,次数+1;如果我们升级失败但没有降为0级,即等级不变:
(
1
−
α
)
∗
(
1
−
β
)
∗
(
d
p
[
i
+
1
]
−
d
p
[
i
]
)
(1-\alpha)*(1-\beta)*(dp[i+1]-dp[i])
(1−α)∗(1−β)∗(dp[i+1]−dp[i]),前面是发生的概率,很好理解,后面的话是发生这种事件的次数,即我们从
i
i
i级升到
i
+
1
i+1
i+1级的次数;如果我们升级失败且等级降为0:
(
1
−
α
)
∗
β
∗
d
p
[
i
+
1
]
)
(1-\alpha)*\beta*dp[i+1])
(1−α)∗β∗dp[i+1]),当发生时,我们需要重新升到
i
+
1
i+1
i+1级,即乘上升到
i
+
1
i+1
i+1级的期望。
2.若不使用:
X
=
d
p
[
i
+
1
]
=
d
p
[
i
+
1
]
+
1
X=dp[i+1]=dp[i+1]+1
X=dp[i+1]=dp[i+1]+1
解释一下 :我们不使用这本书升到 i + 1 i+1 i+1级,但是我们依旧购买了这本书,次数+1.
因此我们得到转移方程:
d
p
[
i
+
1
]
=
1
A
B
∑
a
,
b
m
i
n
{
X
,
Y
}
dp[i+1]=\frac {1}{AB}\sum_{a,b}min\{ X,Y\}
dp[i+1]=AB1a,b∑min{X,Y}
因为我们要采取最优策略升级,那么如果我们要想使用该本书升级,那么需满足使用的期望
≤
\le
≤不使用的期望
(
Y
≤
X
)
(Y\le X)
(Y≤X)
化简得到
d
p
[
i
+
1
]
≥
d
p
[
i
]
∗
α
−
α
β
+
β
α
dp[i+1] \geq dp[i]*\frac{\alpha-\alpha \beta+\beta}{\alpha}
dp[i+1]≥dp[i]∗αα−αβ+β
观察该式子,发现
α
−
α
β
+
β
α
\frac{\alpha-\alpha \beta+\beta}{\alpha}
αα−αβ+β越小的书越容易被使用,即书的
α
−
α
β
+
β
α
\frac{\alpha-\alpha \beta+\beta}{\alpha}
αα−αβ+β越小越好。
那么我们将所有书的
α
−
α
β
+
β
α
\frac{\alpha-\alpha \beta+\beta}{\alpha}
αα−αβ+β排序,枚举取前
t
t
t小的书,那么
化简
d
p
[
i
+
1
]
=
d
p
[
i
]
+
1
+
(
1
−
α
)
∗
(
1
−
β
)
∗
(
d
p
[
i
+
1
]
−
d
p
[
i
]
)
+
(
1
−
α
)
∗
β
∗
d
p
[
i
+
1
]
)
dp[i+1]=dp[i]+1+(1-\alpha)*(1-\beta)*(dp[i+1]-dp[i])+(1-\alpha)*\beta*dp[i+1])
dp[i+1]=dp[i]+1+(1−α)∗(1−β)∗(dp[i+1]−dp[i])+(1−α)∗β∗dp[i+1])得:
d
p
[
i
+
1
]
=
A
B
+
d
p
[
i
]
∗
∑
前
t
小
α
+
β
−
α
∗
β
t
−
∑
前
t
小
1
−
α
dp[i+1]=\frac{AB+dp[i]*\sum_{前t小}{\alpha+\beta-\alpha*\beta}}{t-\sum_{前t小}{1-\alpha}}
dp[i+1]=t−∑前t小1−αAB+dp[i]∗∑前t小α+β−α∗β.
然后枚举递推就可以了,时间复杂度
O
(
k
∗
A
∗
B
)
O(k*A*B)
O(k∗A∗B)
code:
struct Node {
int a, b;
double val;
bool operator < (const Node &q) const {
return val < q.val;
}
}q[N];
void solve() {
int k, A, B;
cin >> k >> A >> B;
vector<double> f(k + 1, 0);
int tot = 0;
for(int i = 0; i < A; i++)
for(int j = 0; j < B; j++) {
tot++;
q[tot] = {i, j};
if(i) q[tot].val = 1.0 * (A * j - i * j) / (i * B);
else q[tot].val = 1e18;
}
sort(q + 1, q + 1 + tot);
for(int i = 0; i < k; i++) {
f[i + 1] = 1e20;
double s1 = 0, s2 = 0;
for(int j = 1; j <= tot; j++) {
s1 += 1.0 * q[j].a / A + 1.0 * q[j].b / B - 1.0 * q[j].a / A * q[j].b / B;
s2 += 1 - 1.0 * q[j].a / A;
f[i + 1] = min(f[i + 1], 1.0 * (A * B + f[i] * s1) / (j - s2));
}
}
// for(int i = 0; i <= k; i++) D(f[i]);
printf("%.3lf\n", f[k]);
}