逃掉比赛来这里写数位DP的小结
( ext说到数位DP,做了几道题之后,会发现全都是一个格式下来的)
$ ext无非就是这么一个格式 : $
int dfs(位置,限制1,限制2,限制3,.......) {
if(最后一位) return 数量;
if(满足限制&&f[]!=-1) return f[位置][限制1][限制2][限制3][....];
枚举上界 = 是最高位 ? 最高位 : 最大数 ;
int ans = 0 ;
for(遍历每个可能的数) {
if(满足限制) {
ans += dfs(位置-1,限制....)
}
}
if(满足限制) f[....] = ans ;
return ans ;
}
int calc(int x) {
len = 0 ;
while(x) {
num[++len] = x % bit ;
x /= bit ;
}
memset(f,-1,sizeof f);
return dfs(len,限制.....)
}
int main () {
in(l,r) ;
out(calc(r)-calc(l-1));
}
然后我们惊奇的发现,我们 需要考虑的就是这么几个限制了
然后,我们通常是要考虑的限制是: 是否有前导零,是否是上界
我们的模板就变成了
int dfs(位置,限制1,限制2,限制3,lead,limit) {
if(最后一位) return 数量;
if(满足限制&&!lead&&!limit&&f[]!=-1) return f[位置][限制1][限制2][限制3];
枚举上界 = limit ? num[len] : bit-1 ;
int ans = 0 ;
for(遍历每个可能的数) {
if(满足限制) {
ans += dfs(位置-1,限制..,lead&&(i==0),limit&&(i==bit-1))
}
}
if(满足限制) f[....] = ans ;
return ans ;
}
int calc(int x) {
len = 0 ;
while(x) {
num[++len] = x % bit ;
x /= bit ;
}
memset(f , -1 , sizeof f ) ;
return dfs(len,限制..,1,1);
}
int main () {
in(l,r) ;
out(calc(r)-calc(l-1));
}
下面看几个题目咯
ZJOI2010数字计数
这道题我们需要统计每个区间内出现数码的个数,考虑统计一个sum
然后下一步搜索dfs(pos-1,sum+(i==d)&&(i||!lead),....) ;
与上面这道题十分相似的是这个
烦人的数学作业
和上一道题的解法相同,统计出数码出现次数然后*数码就好了