数位DP 看起来感觉是很高端大气上档次的东东 可惜在两位师傅的指导下,我貌似还是不算太会,所以我下定决心好好学习数位DP,那么我先从水题HDOJ 2089开始
简单介绍下数位DP:
以【1, 56724】区间为例。
第一位必须是0-4的情况下才会满足后四位是任意的数字;同理第二位必须是0-5的情况下彩绘满足后三位是任意的数字;以此类推下去。。。
F(A,B) = F(B,0)-F(A-1,0)
暴力+存储 = 记忆化搜索
7k大神数位DP模版:
int dfs(int i, int s, bool e) {
if (i==-1) return s==target_s;
if (!e && ~f[i][s]) return f[i][s];
int res = 0;
int u = e?num[i]:9;
for (int d = first?1:0; d <= u; ++d)
res += dfs(i-1, new_s(s, d), e&&d==u);
return e?res:f[i][s]=res;
}
其中:
f为记忆化数组;
i为当前处理串的第i位(权重表示法,也即后面剩下i+1位待填数);
s为之前数字的状态(如果要求后面的数满足什么状态,也可以再记一个目标状态t之类,for的时候枚举下t);
e表示之前的数是否是上界的前缀(即后面的数能否任意填)。
for循环枚举数字时,要注意是否能枚举0,以及0对于状态的影响,有的题目前导0和中间的0是等价的,但有的不是,对于后者可以在dfs时再加一个状态变量z,表示前面是否全部是前导0,也可以看是否是首位,然后外面统计时候枚举一下位数。It depends.
!e==true 表示后面的数,不可以为任意的数。 ~f[ i ][ s ] => f[ i ][ s ] != -1 记忆化搜索 同时满足俩个条件则返回f[ i ][ s ];
当e为false时表示后面的数位可以为任意的数 故此后面的位可以枚举从0-9。 反之亦然, 当e==true时代表后面的数位不可以为任意的数 后面的位只可以枚举从0-num[ i ]。
HDOJ 2089
给一段范围【a, b】 求出其中不包含64或4的数的个数。
未完待续。。。