数位DP小结

逃掉比赛来这里写数位DP的小结

\(\text说到数位DP,做了几道题之后,会发现全都是一个格式下来的\)

$\text无非就是这么一个格式 : $

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),....) ;

题解链接

与上面这道题十分相似的是这个

烦人的数学作业

和上一道题的解法相同,统计出数码出现次数然后*数码就好了

题解链接

[SCOI2009]windy数

题解链接

数位DP栏

posted @ 2019-11-01 20:14  _L_Y_T  阅读(191)  评论(0编辑  收藏  举报