之前说过要做个专题,虽然隔了好长时间。。但说话还是算数的,把之前做的ppt翻出来贴上,好吧,我就是懒。。
(回头看看,良心发现,再补全些。。)
见识的还是少,欢迎讨论啊~~
数位DP
•问题:在给定区间
[A,B]
内,找满足要求的数。
•
要求一般和数大小无关,而与数的组成有关
•
例如,递增的,
1234,2579…
•
双峰的,
19280,26193…
•
含
49
的,
49, 149, 1492…
•
整除
13
的,
26, 39…
•
麻烦在于,规模大,位数
>100
,不能枚举。
•并且
区间往往不是整百整千,需要小心处理边界
•
注意
–
记忆化搜索思路清晰
–
开适当空间(能省则省)
–
寻找合适的状态,简化计算量
例hdu3886
•
题目大意:给一定区间
[A,B]
,一串由
/,\,-
组成的符号串。求满足符号串的数字个数。
•
/
表示数字从左到右递增
•
\
表示数字从左到右递减
•
-
表示数字从左到右相等
•
例如
:
•
/-\
•
1221,123455543
•
数据规模
:
•
A,B<=10^100
分析
F(A,B) = F(B,0)-F(A-1,0) //区间[A,B]中符合要求的数量 = 区间[0,B]的 - 区间[0,A-1]的
因此只要考虑区间[0,num]的情况就好了
暴力+存储= 记忆化搜索
•
暴力
•
暴力枚举每一位
(0..9),
注意区间边界
;
与符号的匹配。
•递归函数为 int
dfs
(
i,j,k,flag
)
•表示
枚举第
i
位的数,匹配
str
[j],
前一位是
k
,是否达到上限
(flag=
true,false
), 返回此时符合要求的数量
•注意边界,如果
达到了上限则只能枚举
0..num[
i
]
,否则可以枚举
0..9
例如 num[] = 157, 枚举到14*时,个位可以为0..9,但是枚举到15*时,个位只能为0..7
•
存储
•
dfs
(
i,j,k,flag
)
•
设状态与递归参数一致
f[
i
][j][k][flag]
,表示当枚举到第
i
位的数,匹配
str
[j],
前一位是
k
,是否达到上限
(flag=
true,false
)
时,满足要求的数字个数。
•
dfs
的过程,相当于在填充
f
,
f
的空间
O(100*10*10*2)
,则
dfs
的时间
O(20000)
实现
•
1.
空间优化,只需记录
flag=false
时的值。因为
flag=true
的值只会计算一次,不是冗余计算,不用记录。
–
(不一定要开和参数一样的数组,适当变换下,分成几种情况开多个数组,可以节省下内存)
•
2.
前导
0
不算数,不能和符号串匹配。特判下即可
–
如
,-/,0003(X),0113
•
3.1234
匹配
//
,会被算成俩个。特判下即可
•
4.
个位放在
f[0][…]
,或者说157要存成num[] = 751,且只记录
flag=false
的值时,
f
与数
A,B
无关!可以反复利用,对于有多组输入样例的问题速度更快
其他类型
•
整除13
•
dfs
(
i
, m,flag)
•
枚举第
i
位数,前面枚举出的数模
13
的余数
m
,是否到达上限
flag
•
整除自身各位数CF55D
•
dfs
(
i
, m,l, flag)
•
枚举第
i
位数,前面枚举出的数模
LCM(0..9)
,
LCM(
前面枚举出的数
)
,是否达到上限
•
包含”49”
•
dfs
(
i
, k,find, flag)
•
枚举第
i
位数,前一位是
k
,是否已包含
”49”(find=true,false)
,是否达到上限
•
分类讨论:
前一
位是否为
4
,当前是否已包含“
49
”
部分解题报告:(习惯写在代码末尾...)
POJ 3252 Round Number
HDU 3709 Balanced Number
HDU 3652 B-number
codeforce 55D Beautiful numbers
写到后来发现这已经成了模板题了,遇到问题,不用想太仔细,直接套上模板,快速、简单、准确。