参考博客: https://www.zybuluo.com/zsh-o/note/1175045
此类问题,一般用递推的思想去考虑比较简单。跟普通的dp差不多,前面的子问题可以重复使用。

例题1
https://ac.nowcoder.com/acm/contest/697/A
题解
这个题其实就是抛硬币连续k次正面的变形。
在还没看博客之前做着题的时候,我想的是,走到第i个点需要1秒的期望,2秒的期望,3秒的期望,4秒的期望。。。。。
会发现这个根本就不可做。如果每颗雷的概率相同的话,还能用错位相减推出通项公式。
可以采用递推的方式:
f[i] : 成功排掉第i颗雷所需的期望时间
递推关系:
f
[
i
]
=
a
i
b
i
(
f
[
i
−
1
]
+
1
)
+
(
1
−
a
i
b
i
)
(
f
[
i
−
1
]
+
1
+
f
[
i
]
)
f[i] = \frac{a_i}{b_i}(f[i-1]+1)+(1-\frac{a_i}{b_i})(f[i-1]+1+f[i])
f[i]=biai(f[i−1]+1)+(1−biai)(f[i−1]+1+f[i])
成功排掉第i颗雷+不成功需要重新排
化简之后
f
[
i
]
=
b
i
a
i
(
f
[
i
−
1
]
+
1
)
f[i] = \frac{b_i}{a_i}(f[i-1]+1)
f[i]=aibi(f[i−1]+1)
代码
#include <bits/stdc++.h>
using namespace std;
// f[i] : 成功排掉第i个雷的期望时间
// f[i] = a/b*(f[i-1]+1)+(1-a/b)*(f[i-1]+1+f[i])
// f[i] = b/a*(f[i-1]+1);
const int mod = 1e9+7;
const int maxn = 1e6+5;
typedef long long ll;
ll pw(ll x, ll n) {
ll ret = 1;
while(n) {
if(n&1) ret = ret*x%mod;
x = x*x%mod;
n >>= 1;
}
return ret;
}
ll f[maxn];
int main() {
int n;
scanf("%d", &n);
ll a,b;
for(int i = 1; i <= n; ++i) {
scanf("%lld%lld", &a, &b);
f[i] = (b*pw(a,mod-2)%mod*((f[i-1]+1)%mod))%mod;
}
printf("%lld\n", f[n]);
return 0;
}
例题2
https://blog.youkuaiyun.com/Link_Ray/article/details/89292941
例题3
https://cometoj.com/contest/37/problem/B?problem_id=1529
题解
设利润为X。售价为q,所给的钱为p。
E
(
X
)
=
E
(
q
−
p
)
=
p
−
l
r
−
l
(
q
−
E
(
p
)
)
+
(
1
−
p
−
l
r
−
l
)
∗
0
E(X) = E(q-p) = \frac{p-l}{r-l}(q-E(p))+(1-\frac{p-l}{r-l})*0
E(X)=E(q−p)=r−lp−l(q−E(p))+(1−r−lp−l)∗0
看做离散型来分析
E
(
p
)
=
L
+
L
+
1
+
⋯
+
R
E(p) = L+L+1+\dots+R
E(p)=L+L+1+⋯+R
E
(
p
)
=
R
(
R
+
1
)
2
−
L
(
L
−
1
)
2
=
L
+
R
2
E(p) = \frac{R(R+1)}{2}- \frac{L(L-1)}{2} = \frac{L+R}{2}
E(p)=2R(R+1)−2L(L−1)=2L+R
可以得出E(X)是一个二次函数,且p的范围在[l,r]之间,因为小于l那么答案就是0,大于r的话不会比选r更优。
代码
#include <bits/stdc++.h>
using namespace std;
#define FOR0(a,b) for(int i = a; i < b; ++i)
#define FORE(a,b) for(int i = a; i <= b; ++i)
typedef long long ll;
typedef pair<int,int> pii;
int main() {
double L,R,l,r;
cin >> l >> r >> L >> R;
double t1 = (L+R)/2;
double t2 = r-l;
double ans = 0;
double t = (t1+l)/2;
if((t1+l)/2 >= l && (t1+l)/2 <= r) {
ans = (t-l)/t2*(t1-t);
} else {
ans = max(0.0, t1-r);
}
printf("%.4lf\n", ans);
return 0;
}
例题4
期望的顺推与逆推:
参考:https://blog.youkuaiyun.com/myjs999/article/details/81022546
-
涂格子1
n个格子,每次随机涂一个,求涂满m个格子的期望次数。
设 f[i]: 涂完i个格子所需的期望次数
易知f[m] = 0,采用逆推。
f
[
i
]
=
(
i
n
f
[
i
]
+
n
−
i
n
f
[
i
+
1
]
)
+
1
f[i] = (\frac{i}{n}f[i]+\frac{n-i}{n}f[i+1])+1
f[i]=(nif[i]+nn−if[i+1])+1
-
涂格子2
n个格子,每次随机涂一个,求涂m次后期望涂色格子数。
设f[i]:涂了i次的染色格子的期望个数
易知f[0] = 0,采用顺推。
f[i] = 涂成功+没涂成功
f
[
i
]
=
n
−
f
[
i
−
1
]
n
∗
1
+
f
[
i
−
1
]
f[i] = \frac{n-f[i-1]}{n}*1+f[i-1]
f[i]=nn−f[i−1]∗1+f[i−1]
-
涂格子3
有n个格子,每次会涂一个格子,其中涂第i个格子的概率是 p i p_i pi( ∑ i = 1 n p i = 1 \sum^{n}_{i=1}{p}_i =1 ∑i=1npi=1)。求每个格子都被涂色的期望次数。
这个和1其实很类似,因为每个格子只能涂一次且概率不同,所以没法把“格子数量”当成一维状态,只能使用状压。
f[S]:状态S到全部颜色都被涂的期望次数。
当
S
=
2
n
−
1
S = 2^n-1
S=2n−1时,
f
[
S
]
=
0
f[S] = 0
f[S]=0。
采用逆推
f
[
S
]
=
∑
i
=
0
n
(
p
i
∗
f
[
S
∣
2
i
]
)
+
1
f[S] = \sum_{i=0}^{n}(p_i*f[S|2^i]) +1
f[S]=i=0∑n(pi∗f[S∣2i])+1
无论从哪里转移而来,此次的次数都要加1。
这里i必须是S中为0的位置。
例题5
https://cometoj.com/contest/37/problem/C
题解
考虑每个点集对期望的贡献。当一个点集有i个点,那么其内部就有
i
∗
(
i
−
1
)
2
\frac{i*(i-1)}{2}
2i∗(i−1)条边,全部消去的概率是
(
x
y
)
i
∗
(
i
−
1
)
2
(\frac{x}{y})^{\frac{i*(i-1)}{2}}
(yx)2i∗(i−1),贡献则是
(
x
y
)
i
∗
(
i
−
1
)
2
∗
1
(\frac{x}{y})^{\frac{i*(i-1)}{2}}*1
(yx)2i∗(i−1)∗1,那么答案便是
∑
i
=
0
n
(
C
n
i
∗
(
x
y
)
i
∗
(
i
−
1
)
2
∗
1
)
\sum_{i=0}^{n}(C^{i}_{n}*(\frac{x}{y})^{\frac{i*(i-1)}{2}}*1)
i=0∑n(Cni∗(yx)2i∗(i−1)∗1)
代码
#include <bits/stdc++.h>
using namespace std;
#define FOR0(a,b) for(int i = a; i < b; ++i)
#define FORE(a,b) for(int i = a; i <= b; ++i)
typedef long long ll;
typedef pair<int,int> pii;
const int mod = 998244353;
const int maxn = 1e5+5;
ll inv[maxn], C[maxn];
ll pw(ll x, ll n) {
ll ret = 1;
while(n) {
if(n&1) ret = ret*x%mod;
x = x*x%mod;
n >>= 1;
}
return ret;
}
int n;
int main() {
ll x,y;
scanf("%d%lld%lld", &n, &x, &y);
inv[1] = 1;
for(ll i = 2; i <= n; ++i) {
inv[i] = (mod-mod/i)*inv[mod%i]%mod;
}
C[0] = 1; C[1] = n;
for(ll i = 2; i <= n; ++i)
C[i] = C[i-1]*inv[i]%mod*(n-i+1)%mod;
ll ans = 0;
ll p = x*pw(y,mod-2)%mod;
ans = 1;
for(ll i = 1; i <= n; ++i) {
ans += C[i]*pw(p,i*(i-1)/2)%mod;
ans %= mod;
}
printf("%lld\n", ans);
return 0;
}
3495



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



