前言
大概就是拿着一些普通的题目扯淡一下?
绝大部分来自BZOJ
因为是大部分是中文题所以放个链接,不占过大篇幅qwq
题目
HDU2955
看起来非常的像一个背包,但是费用是实数的话是很难存并且实现的。所以考虑令DP[x] 表示已经获得了x的最小风险。
然后在最后找答案的时候判断一下当前最大的x满足dp[x]满足风险要求。
Tag:DP
Code
BZOJ1076
对于当前状态可以简单表示为当前已经获得了哪一些物品[可以二进制的简单表示],已经扔了了多少物品,显然只有这两个东西就可以求出下一步的状态并且及时停下。
接下来的说法可能会有一点混乱。
简单来说就是令dp[s][i] 表示当前已经获得的物品的集合的表示为s,当前已经扔出了i个东西,那么我们等概率的获得所有的物品,那么对于当前的这个物品是选择还是不选择呢?
听起来似乎非常的复杂,但是事实上,只要考虑选择更优还是不选择更优就好了,也就是记忆化搜索[其实在这里写成递推一样的形式也是可以的,只是稍微有些麻烦[个人看法]],然后记忆化搜索的话就很好考虑了,考虑选择或者不选择哪个更加优秀就选择哪一种方案即可。
Tag:DP
Code
BZOJ1415
题意的话就是聪聪朝着可可走两步,然后可可随机的走一步或者不动。这样就可以发现游戏一定是在有限步数内完成的,聪聪可可每过一轮距离至少会变近1,至多会变近3,不过简单来说就是,状态之间没有环。
那么就可以简单的转移啦。然后记忆化搜索的效果也非常好,代码短而优美[虽然我的大概算不上]。
Code
BZOJ2438
JC一定是有一个特殊的最优的询问方案的,那么问题来了,这个询问方案是什么呢?贪心的考虑,肯定询问的人越少越好。
每次查到一个人之后,那么他能到达的所有人包括他自身都是可以被被确定下来的。很容易想到首先Tarjan来缩点,然后每次查询就一定为入度为0的点。
但是,事情没有那么简单。如果一个JC已经确定了n-1个人的身份了,然而却没有人认识最后一个人。小镇只有一个杀手,在这答案已经呼之欲出的时候,还需要查这个人吗?
答案是显然不需要。
所以需要查的个数就等于,入度为0的联通块的个数,如果存在一个入度为0,大小为1,而且所有能到达的联通块都可以被其他联通块到达的联通块,那么需要查找的个数减去1。
Tag:贪心,Tarjan
Code
BZOJ2752
简单来说就是考虑一个点的贡献是多少?是它的值*它被包含的方案数量。
对于dis[x,x+1]会被算到
(x−l+1)∗(r−(x+1)+1)
(
x
−
l
+
1
)
∗
(
r
−
(
x
+
1
)
+
1
)
次
然后怒推一波式子,用线段树维护一波就结束了。但是似乎当时写的版本会比较复杂?
但是这个不好解决。换个表达方法[?]
维护一个前缀和
n=r-l
sum[r]∗n+sum[r−1]∗(n−1)...+sum[l+1]∗1−sum[l]∗n−sum[l+1]∗(n−1)...−sum[r−1]∗1
s
u
m
[
r
]
∗
n
+
s
u
m
[
r
−
1
]
∗
(
n
−
1
)
.
.
.
+
s
u
m
[
l
+
1
]
∗
1
−
s
u
m
[
l
]
∗
n
−
s
u
m
[
l
+
1
]
∗
(
n
−
1
)
.
.
.
−
s
u
m
[
r
−
1
]
∗
1
dis[l][r]=T1.qu(l,r)−T3.qu(l,r)∗l−T2.qu(l,r)−T3.qu(l,r)∗(r−2∗l)
d
i
s
[
l
]
[
r
]
=
T
1.
q
u
(
l
,
r
)
−
T
3.
q
u
(
l
,
r
)
∗
l
−
T
2.
q
u
(
l
,
r
)
−
T
3.
q
u
(
l
,
r
)
∗
(
r
−
2
∗
l
)
这个可以用线段树解决的,不过稍微有点麻烦,不过其实差不多了。
需要一个等差数列合并,不会,所以用很玄妙的方法写了。
sum[x] 表示从节点1走到节点x的距离是多少,那么对于区间[l,r]的答案就会是
然后用线段树暴力维护[?]
对于上面这个式子,其实可以拆开,然后分别统计
∑r−1x=1(r−x)∗sum[x] ∑ x = 1 r − 1 ( r − x ) ∗ s u m [ x ] 和 ∑ry=l+1(y−l)∗sum[y] ∑ y = l + 1 r ( y − l ) ∗ s u m [ y ]
然后真的可以用线段树暴力维护了。
对于区间加的过程中怎么快速求出对于各区间的贡献,虽然说可以通过数学来推出公式,不过也可以通过预处理来解决。
Code
Tag:数据结构维护计数问题
BZOJ3566
是树形DP吧…没了。
考虑有可能是父节点的向下导。
再记一个f[x] 表示如果点亮f[x]的父亲之后可以往下点亮多少个的期望.
f[x] 表示节点x是被儿子节点导上来的。
g[x] 表示节点x被点亮带来的贡献
F=1−(1−f[x])/(1−f[e[i].x]∗e[i].l);
F
=
1
−
(
1
−
f
[
x
]
)
/
(
1
−
f
[
e
[
i
]
.
x
]
∗
e
[
i
]
.
l
)
;
P(A+B)=P(A)+P(B)−P(A)∗P(B)
P
(
A
+
B
)
=
P
(
A
)
+
P
(
B
)
−
P
(
A
)
∗
P
(
B
)
P(A+B−B)=(P(A+B)−P(B))/(1−P(B))
P
(
A
+
B
−
B
)
=
(
P
(
A
+
B
)
−
P
(
B
)
)
/
(
1
−
P
(
B
)
)
参考了这位
Tag:树形DP
BZOJ1419
dp[x][y] 表示翻到了x张红,y张黑。然后记忆化搜索。非常传统的做法。
然后注意的地方是:
会炸空间,滚动数组。
不过打表似乎有一定的规律,说不定有什么优化方法?如果有的话求教qwq
Tag:DP
BZOJ3191
是一个约瑟夫环问题。之前接触的并不多,不过似乎有一定的套路。
dp[i][j] 表示有i个人在游戏,第j个人胜利的概率
然后就可以简单的推得对于本题的转移
dp[i+1][(j+a[k])
d
p
[
i
+
1
]
[
(
j
+
a
[
k
]
)
不过这样有一定套路可沿的问题倒是可以专门在整理xxx
Tag:DP
BZOJ3091
对于这种把一模一样的问题强行丢到树上表示强烈谴责。其实感觉就是BZOJ2752啊qwq。
然后打了一个LCT来解决就好了。当时还把LCT打错了…然后这里用的做法就是直接用dis[x,x+1]会被算到(x-l+1)*(r-(x+1)+1)的性质来求了。需要同时维护好几个东西…
lsum=1∗a1+2∗a2+...+n∗an
l
s
u
m
=
1
∗
a
1
+
2
∗
a
2
+
.
.
.
+
n
∗
a
n
rsum=1∗an+2∗an−1+...+n∗a1
r
s
u
m
=
1
∗
a
n
+
2
∗
a
n
−
1
+
.
.
.
+
n
∗
a
1
fp=fls+frs+lsumls∗(szrs+1)+rsumrs∗(szls+1)
f
p
=
f
l
s
+
f
r
s
+
l
s
u
m
l
s
∗
(
s
z
r
s
+
1
)
+
r
s
u
m
r
s
∗
(
s
z
l
s
+
1
)
Tag:LCT,树上计数问题
Code
BZOJ1426
dp[x] 表示收集了x张不同的邮票的期望用钱数量
sum[x] 表示期望收集次数(决定花钱的数量)
step=n/(n−i)
s
t
e
p
=
n
/
(
n
−
i
)
sum[i+1]=sum[i]+step
s
u
m
[
i
+
1
]
=
s
u
m
[
i
]
+
s
t
e
p
基础的式子
dp[i]=(dp[i+1]+sum[i+1])∗(1−i/n)+(i/n)∗(dp[i]+sum[i+1])
d
p
[
i
]
=
(
d
p
[
i
+
1
]
+
s
u
m
[
i
+
1
]
)
∗
(
1
−
i
/
n
)
+
(
i
/
n
)
∗
(
d
p
[
i
]
+
s
u
m
[
i
+
1
]
)
然后移项
dp[i+1]=(dp[i]−(i/n)∗(dp[i]+sum[i+1]))/((n−i)/n)−sum[i+1]
d
p
[
i
+
1
]
=
(
d
p
[
i
]
−
(
i
/
n
)
∗
(
d
p
[
i
]
+
s
u
m
[
i
+
1
]
)
)
/
(
(
n
−
i
)
/
n
)
−
s
u
m
[
i
+
1
]
Tag:DP?
BZOJ4832
dp[x][cnt1][cnt2][cnt3][hp] 表示攻击了x轮,血量扣除了hp,血量为1的奴隶主个数为cnt1,之后以此类推的概率。
一种简单易懂的状态…不过并不优。
如果把存的概率改成期望扣血量,那么就可以省一维。然后如果轮数表示剩余多少轮,然后就不用每个T都计算…一下子就只跑4ms了呢。
Tag:DP
BZOJ3029
可以发现,要求满足的只有
1.需要胜利l场;
2.背包容量大于碎片个数
对于第一个要求只需要dp多记录一维当前胜利场数,对于第二个要求,发现胜利给的背包容量可能会很大,但是最多只会用到获得碎片个数个容量。
然后就记dp[x][l][p] 表示前x场已经结束,胜利了l场,min(最大碎片获得数量,背包容量-世纪碎片获得数量)=p的概率。
然后就没有了?对于最后一维可能为负值,只需要加上一个base即可。
Tag:DP
BZOJ2510
简单来说就是一个类似于矩阵乘法快速幂的东西,事实上除了概率/期望DP以外这种做法也非常的常见。
所以说看到这道题我们考虑当前已经进行2^K次操作,dp[l] 为编号为x的球到x+l位置的概率是多少。
然后p[x] 表示位置在x的球的期望个数。
Tag:快速幂
BZOJ1417
首先我们可以发现我们不考虑块里面到底有什么和块内的联通情况,需要考虑的只有所有块的大小。那么考虑状态内记各个块的大小。然后可以用map来解决。
那么对于当前状态,设有m个块,每个块的大小分别为a[1],a[2]…a[m],
∑mi=1C2a[i]
∑
i
=
1
m
C
a
[
i
]
2
种情况不发生改变,以及
a[x]∗a[y]
a
[
x
]
∗
a
[
y
]
种情况,x和y合并。
然后
dp[s]=(∑dp[ns]∗p[ns]+dp[s]∗∑mi=1C2a[i])/C2n+1
d
p
[
s
]
=
(
∑
d
p
[
n
s
]
∗
p
[
n
s
]
+
d
p
[
s
]
∗
∑
i
=
1
m
C
a
[
i
]
2
)
/
C
n
2
+
1
之后移项。使用记忆化搜索方便的求出答案。
关于复杂度,可以写一个普通的深搜,搜出将30分成数个部分的方案数,是4565(大概不会算错?)
Tag:记忆化搜索
BZOJ2676
首先看到这一类问题,先考虑转化成二分然后变成判定问题这样的话就简单很多了[?]
那么对于当前的p,需要快速的求出期望获得的得分。N比较大,能接受的要么是
O(log2n)
O
(
l
o
g
2
n
)
要么
O(n1/2)
O
(
n
1
/
2
)
,看起来前者的可能性比较大。
然后猜测就是到这里为止。
由于每一关的结构都是类似的[也可以说是转移方程],想到矩阵乘法快速幂,然后这样也可以有效的把N带来的复杂度减小。然后这样可以不可以呢?答案是可以的。
状态数量只有R*Q,表示当前连胜场数和当前的血量。然后矩阵乘法也可以接受。就解决问题了。
需要注意的地方:
S要开long long!!!
Tag:矩阵乘法,快速幂
BZOJ2318
如果当前投出正面更优 那么就想投出正面,否则想投出反面。
令f[n] 表示当前石子数量为n先手胜率,g[n] 表示当前式子数量为n的后手胜率。
考虑之后状态的胜利概率,然后再转移。
然后就是n特别大可以直接缩小。因为之后的概率几乎不变。
Tag: 博弈[?]
总结
这里整理的是一些较为简单[?]并不利用期望的线性性质[也不一定?]并且状态之间没有环[不包括自环?]的概率/期望DP,和一些表面并不是DP,但是实际上和概率/期望有着较大联系的题目。
那么可以分为这么几类。
1. 可能会延伸出一些比较特别的形式:
- 特殊期望模型
- BZOJ1426
- 价值作为下标[DP常见]
- HDU2955
- 快速幂
- BZOJ2510
- BZOJ2676
- 记忆化搜索后取最优决策 (某种意义上可以算博弈?)
- BZOJ1076
- BZOJ2318
- 某些状态到达的概率很小可以忽略
- 那道题好像被归到期望线性性质里去了
- 二分转为判定问题
- BZOJ2676
- 特殊模型
- BZOJ3191(约瑟夫环)
- 滚动数组[其实这个也没啥?]
- BZOJ1419
2.图论
- BZOJ2438
总之这样的题目大部分情况下通过推一推公式或者转移方程,或者理解题意之后都比较简单?与其说是考概率/期望多一点,不如说是考其他知识点的时候顺带一下概率。当然和特别复杂的算法结合在一起也能出很难的题目吧?