@@ -22,14 +22,15 @@ https://leetcode.cn/problems/shortest-common-supersequence/solution/cong-di-gui-
22
22
23
23
前缀/后缀之间的转移,例如从 f[i-1] 转移到 f[i],或者从 f[j] 转移到 f[i]
24
24
LC70 爬楼梯 https://leetcode.cn/problems/climbing-stairs/
25
- - 变形: 有花费 LC746 https://leetcode.cn/problems/min-cost-climbing-stairs/
25
+ - 有花费 LC746 https://leetcode.cn/problems/min-cost-climbing-stairs/
26
26
- https://atcoder.jp/contests/dp/tasks/dp_a
27
27
- https://atcoder.jp/contests/dp/tasks/dp_b
28
- - 变形: 有障碍物 https://atcoder.jp/contests/abc129/tasks/abc129_c
28
+ - 有障碍物 https://atcoder.jp/contests/abc129/tasks/abc129_c
29
29
LC198 打家劫舍 https://leetcode.cn/problems/house-robber/
30
- - 变形:值域打家劫舍 LC740 https://leetcode.cn/problems/delete-and-earn/
31
- - 变形:恰好选 floor(n/2) 个 https://atcoder.jp/contests/abc162/tasks/abc162_f
32
- - 变形:矩阵打家劫舍 https://codeforces.com/problemset/problem/1195/C
30
+ - 值域打家劫舍 LC740 https://leetcode.cn/problems/delete-and-earn/
31
+ - 分组+值域打家劫舍 https://atcoder.jp/contests/abc403/tasks/abc403_d
32
+ - 恰好选 floor(n/2) 个 https://atcoder.jp/contests/abc162/tasks/abc162_f
33
+ - 矩阵打家劫舍 https://codeforces.com/problemset/problem/1195/C
33
34
- 环形 LC213 https://leetcode.cn/problems/house-robber-ii/
34
35
- 环形 https://atcoder.jp/contests/abc251/tasks/abc251_e
35
36
LC2369 https://leetcode.cn/problems/check-if-there-is-a-valid-partition-for-the-array/ 1780
@@ -61,6 +62,7 @@ https://codeforces.com/problemset/problem/1920/E 2000
61
62
https://codeforces.com/problemset/problem/2027/D2 2200 在 DP 数组上滑窗
62
63
https://codeforces.com/problemset/problem/2045/H 2200
63
64
https://codeforces.com/problemset/problem/6/D 2600
65
+ https://atcoder.jp/contests/dp/tasks/dp_t 状态设计
64
66
https://www.luogu.com.cn/problem/P2258
65
67
66
68
输出具体方案
@@ -117,6 +119,8 @@ https://codeforces.com/contest/2043/problem/C
117
119
118
120
网格路径问题 网格图 DP
119
121
技巧:对于求方案数的题目,可以初始化 f[0][1] = 1,从而避免单独讨论左上角 f[1][1] 的计算
122
+ - [63. 不同路径 II](https://leetcode.cn/problems/unique-paths-ii/)
123
+ - https://atcoder.jp/contests/dp/tasks/dp_h
120
124
- [64. 最小路径和](https://leetcode.cn/problems/minimum-path-sum/)
121
125
- 变形:连续性 & 上下界思想 https://codeforces.com/contest/1695/problem/C
122
126
- https://atcoder.jp/contests/arc137/tasks/arc137_b 也用到了这个思想
@@ -1291,7 +1295,8 @@ func _(abs func(int) int) {
1291
1295
// - 变形,需要多加一个维度 https://atcoder.jp/contests/abc275/tasks/abc275_f
1292
1296
// https://atcoder.jp/contests/abc159/tasks/abc159_f 贡献
1293
1297
// https://atcoder.jp/contests/agc020/tasks/agc020_c 所有非空子集和的中位数
1294
- // NOIP06·提高 金明的预算方案(也可以用树上背包做)https://www.luogu.com.cn/problem/P1064
1298
+ // https://atcoder.jp/contests/dp/tasks/dp_x 邻项交换法
1299
+ // https://www.luogu.com.cn/problem/P1064 NOIP06·提高 金明的预算方案(也可以用树上背包做)
1295
1300
// EXTRA: 恰好装满(相当于方案数不为 0)LC416 https://leetcode.cn/problems/partition-equal-subset-sum/
1296
1301
// 必须定义成恰好装满(紫书例题 9-5,UVa 12563)https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=441&page=show_problem&problem=4008
1297
1302
// EXTRA: 背包容量为 0 https://codeforces.com/problemset/problem/366/C 1900
@@ -1583,12 +1588,13 @@ func _(abs func(int) int) {
1583
1588
// 每个物品的体积都是 1
1584
1589
// 如果题目要求每种物品至少选一个,可以把每个 cnts[i] 都减一,maxW 减去 len(cnts),这样就转换成了每种物品至少选 0 个的情况了
1585
1590
// 讲解 https://leetcode.cn/problems/find-the-original-typed-string-ii/solutions/2966856/zheng-nan-ze-fan-qian-zhui-he-you-hua-dp-5mi9/
1591
+ // https://atcoder.jp/contests/dp/tasks/dp_m
1586
1592
// 挑战 pp.68-69 多重集组合数
1587
1593
// 另见 math_comb.go 中的「多重集组合数」容斥做法
1588
1594
// https://codeforces.com/problemset/problem/156/C 也可以用容斥
1589
1595
boundedKnapsackWays := func (cnts []int , maxW int ) int {
1590
1596
// 从 len(cnts) 种物品中选出【至多】maxW 个物品的方案数
1591
- // f[i+1][j] 表示从前 i 种物品中选恰好 j 个物品的方案数(第一维度优化掉 )
1597
+ // f[i+1][j] 表示从前 i 种物品中选【恰好】 j 个物品的方案数(优化掉第一个维度 )
1592
1598
f := make ([]int , maxW + 1 )
1593
1599
f [0 ] = 1
1594
1600
for _ , c := range cnts {
@@ -2128,6 +2134,8 @@ func _(abs func(int) int) {
2128
2134
σ²(x) = sum(x²)/n - (sum(x)/n)²
2129
2135
2130
2136
概率 DP
2137
+ https://atcoder.jp/contests/dp/tasks/dp_i 入门题
2138
+ - 在本题中,选或不选不是人为决定的,而是由概率决定的
2131
2139
https://codeforces.com/problemset/problem/16/E 1900
2132
2140
https://codeforces.com/problemset/problem/540/D 1900
2133
2141
https://codeforces.com/problemset/problem/678/E 2200
@@ -2143,7 +2151,7 @@ func _(abs func(int) int) {
2143
2151
https://www.luogu.com.cn/problem/P2719 用组合数学做
2144
2152
2145
2153
期望 DP
2146
- 入门题 https://atcoder.jp/contests/abc280/tasks/abc280_e
2154
+ https://atcoder.jp/contests/abc280/tasks/abc280_e 入门题
2147
2155
https://atcoder.jp/contests/abc350/tasks/abc350_e
2148
2156
- 如果状态转移左右两边都包含 f[i],则需要移项化简
2149
2157
https://atcoder.jp/contests/dp/tasks/dp_j
@@ -2305,6 +2313,7 @@ func _(abs func(int) int) {
2305
2313
// https://codeforces.com/problemset/problem/1598/F 2400 合法括号字符串
2306
2314
// https://codeforces.com/problemset/problem/1550/E 2500 状态设计
2307
2315
// https://www.luogu.com.cn/problem/P3694 前缀和
2316
+ // LC3530 https://leetcode.cn/problems/maximum-profit-from-valid-topological-order-in-dag/ DAG 排列
2308
2317
permDP := func (a []int , check func (int , int ) bool ) int {
2309
2318
n := len (a )
2310
2319
f := make ([]int , 1 << n )
@@ -2961,30 +2970,32 @@ func _(abs func(int) int) {
2961
2970
}
2962
2971
2963
2972
//(旧版写法)做两次记忆化搜索(或者题目只需要考虑上界)
2964
- digitDP2 := func (low , high string , sumUpper int ) int {
2965
- // 返回 <=s 的符合要求的字符串数目
2966
- // TIPS: 某些情况下思考补集会更加容易,即求不符合要求的字符串数目
2973
+ digitDP2 := func (low , high string , k int ) int {
2967
2974
calc := func (s string ) int {
2968
- // 注:如果参数太多可以用 map + struct
2975
+ // 注:如果参数太多可以用 map
2969
2976
memo := make ([][]int , len (s ))
2970
2977
for i := range memo {
2971
- memo [i ] = make ([]int , sumUpper + 1 )
2978
+ memo [i ] = make ([]int , k )
2972
2979
for j := range memo [i ] {
2973
2980
memo [i ][j ] = - 1
2974
2981
}
2975
2982
}
2976
2983
2977
2984
// 第一种写法(前导零不影响答案)
2978
2985
var f func (int , int , bool ) int
2979
- f = func (i int , sum int , isLimit bool ) (res int ) {
2986
+ f = func (i , sum int , isLimit bool ) (res int ) {
2980
2987
if i == len (s ) {
2988
+ if sum > 0 {
2989
+ return
2990
+ }
2981
2991
return 1
2982
- } // sum
2992
+ }
2983
2993
if ! isLimit {
2984
2994
dv := & memo [i ][sum ]
2985
2995
if * dv >= 0 {
2986
2996
return * dv
2987
- } // *dv + sum*int(math.Pow10(len(s)-i))
2997
+ }
2998
+ // *dv + sum*int(math.Pow10(len(s)-i))
2988
2999
defer func () { * dv = res }()
2989
3000
}
2990
3001
@@ -2993,12 +3004,10 @@ func _(abs func(int) int) {
2993
3004
up = int (s [i ] - '0' ) // 'a'
2994
3005
}
2995
3006
2996
- for d := 0 ; d <= up ; d ++ {
2997
- tmp := sum
2998
-
2999
- cnt := f (i + 1 , tmp , isLimit && d == up )
3000
- res = (res + cnt ) % mod
3007
+ for d := range up + 1 {
3008
+ res += f (i + 1 , (sum + d )% k , isLimit && d == up )
3001
3009
}
3010
+ res %= mod
3002
3011
return
3003
3012
}
3004
3013
//res := f(0, 0, true)
@@ -3224,46 +3233,54 @@ func _(abs func(int) int) {
3224
3233
return
3225
3234
}
3226
3235
3227
- /* 倍增优化 DP
3228
- https://codeforces.com/problemset/problem/1175/E 模板题
3236
+ /* 倍增
3237
+ https://oi-wiki.org/basic/binary-lifting/
3238
+ https://atcoder.jp/contests/arc060/tasks/arc060_c 模板题
3239
+ - LC3534 https://leetcode.cn/problems/path-existence-queries-in-a-graph-ii/ 重新编号(下标映射)
3240
+ https://codeforces.com/problemset/problem/1175/E
3229
3241
https://codeforces.com/problemset/problem/1516/D
3230
- https://atcoder.jp/contests/arc060/tasks/arc060_c
3231
3242
https://www.luogu.com.cn/problem/P1081 开车旅行
3232
3243
https://www.luogu.com.cn/problem/P3147 合并数字
3233
3244
https://www.luogu.com.cn/problem/P1613
3234
- 计算重复 https://www.acwing.com/problem/content/296/
3245
+ https://www.acwing.com/problem/content/296/ 计算重复
3235
3246
*/
3236
- binaryLifting := func (segs , qs []struct { l , r int }) []int {
3237
- // 以 CF1175E 为例
3238
- const mx = 19
3239
- f := make ([][mx ]int , 5e5 + 1 )
3240
- for _ , s := range segs {
3241
- l , r := s .l , s .r
3242
- f [l ][0 ] = max (f [l ][0 ], r )
3243
- }
3244
- // 前缀最大值(最右)
3245
- for i := 1 ; i < len (f ); i ++ {
3246
- f [i ][0 ] = max (f [i ][0 ], f [i - 1 ][0 ])
3247
+ binaryLifting := func (left []int , qs []struct { l , r int }) []int {
3248
+ // 以 https://atcoder.jp/contests/arc060/tasks/arc060_c + https://leetcode.cn/problems/path-existence-queries-in-a-graph-ii/ 为例
3249
+ n := len (left )
3250
+ const mx = 17 // bits.Len(uint(n))
3251
+ pa := make ([][mx ]int , n )
3252
+ for i , l := range left {
3253
+ pa [i ][0 ] = l
3247
3254
}
3248
- // 倍增
3249
- for i := 0 ; i + 1 < mx ; i ++ {
3250
- for p := range f {
3251
- f [ p ][i + 1 ] = f [ f [ p ][ i ] ][i ]
3255
+ for i := range mx - 1 {
3256
+ for x := range pa {
3257
+ p := pa [ x ][ i ]
3258
+ pa [ x ][i + 1 ] = pa [ p ][i ]
3252
3259
}
3253
3260
}
3254
3261
3255
3262
ans := make ([]int , len (qs ))
3256
3263
for qi , q := range qs {
3257
3264
l , r := q .l , q .r
3265
+ if l == r {
3266
+ // ans[qi] = 0
3267
+ continue
3268
+ }
3269
+ if l > r {
3270
+ l , r = r , l
3271
+ }
3258
3272
res := 0
3259
- for i := mx - 1 ; i >= 0 ; i -- {
3260
- if f [l ][i ] < r {
3261
- l = f [l ][i ]
3262
- res |= 1 << i
3273
+ for k := mx - 1 ; k >= 0 ; k -- {
3274
+ p := pa [r ][k ]
3275
+ if p > l {
3276
+ res |= 1 << k
3277
+ r = p
3263
3278
}
3264
3279
}
3265
- if f [l ][0 ] >= r {
3266
- ans [qi ] = res + 1
3280
+ res ++
3281
+ r = pa [r ][0 ]
3282
+ if r <= l {
3283
+ ans [qi ] = res
3267
3284
} else {
3268
3285
ans [qi ] = - 1
3269
3286
}
@@ -3277,7 +3294,8 @@ func _(abs func(int) int) {
3277
3294
LC2713 https://leetcode.cn/problems/maximum-strictly-increasing-cells-in-a-matrix/
3278
3295
线段树 LC2407 https://leetcode.cn/problems/longest-increasing-subsequence-ii/ 2280
3279
3296
变量优化 O(n) LC2746 https://leetcode.cn/problems/decremental-string-concatenation/
3280
- https://atcoder.jp/contests/abc339/tasks/abc339_e 入门 值域线段树
3297
+ https://atcoder.jp/contests/dp/tasks/dp_q 入门题 值域树状数组
3298
+ https://atcoder.jp/contests/abc339/tasks/abc339_e 入门题 值域线段树
3281
3299
https://atcoder.jp/contests/dp/tasks/dp_w Lazy 线段树
3282
3300
https://atcoder.jp/contests/arc073/tasks/arc073_d
3283
3301
- https://www.luogu.com.cn/problem/T190609?contestId=48376
@@ -3316,9 +3334,12 @@ func _(abs func(int) int) {
3316
3334
https://codeforces.com/problemset/problem/46/E 1900 前缀最大值/后缀最大值
3317
3335
https://codeforces.com/problemset/problem/479/E 1900
3318
3336
- https://atcoder.jp/contests/abc253/tasks/abc253_e
3337
+ https://atcoder.jp/contests/dp/tasks/dp_t 排列问题的状态设计
3338
+ - 相似题目 https://leetcode.cn/problems/count-the-number-of-inversions/
3319
3339
https://atcoder.jp/contests/abc248/tasks/abc248_c
3320
3340
https://atcoder.jp/contests/diverta2019/tasks/diverta2019_e
3321
3341
https://codeforces.com/problemset/problem/708/E 3100
3342
+ 另见本页面的 boundedKnapsackWays(前缀和优化多重背包方案数)
3322
3343
3323
3344
其他
3324
3345
https://codeforces.com/problemset/problem/1863/F 2600
@@ -3638,6 +3659,7 @@ func _(abs func(int) int) {
3638
3659
https://codeforces.com/problemset/problem/1453/E 2300 好题
3639
3660
https://codeforces.com/problemset/problem/238/C 做到 O(n) ~2400
3640
3661
https://codeforces.com/problemset/problem/1059/E 2400 取往上冲的最高的点(子树)
3662
+ https://atcoder.jp/contests/dp/tasks/dp_p
3641
3663
https://atcoder.jp/contests/abc259/tasks/abc259_f
3642
3664
https://atcoder.jp/contests/abc239/tasks/abc239_e
3643
3665
https://atcoder.jp/contests/abc207/tasks/abc207_f
@@ -4382,6 +4404,7 @@ func _(abs func(int) int) {
4382
4404
// 数位 DP
4383
4405
digitDP , digitDP2 , calcSum , digitDP2D , kth666 ,
4384
4406
4407
+ // 倍增
4385
4408
binaryLifting ,
4386
4409
4387
4410
// 数据结构优化 DP
0 commit comments