小学生都能看懂的数位dp

前言

数位dp其实很久前就知道了,也做过几道和其他算法混在一起的题目,其实通过手玩是能做的

但毕竟是种算法,还是系统学下比较好(节省手玩时间)

模板题

P2602 [ZJOI2010]数字计数

化简题意:求\(0~9\)在一个范围内出现的次数

设数组\(dp_i\)为满\(i\)位每个数字出现的次数,也是说四位我们都算进去而忽略前导0的存在
而实际中显然像0012这样的数字我们是不会统计那两个0的
(满位情况下每个数字出现次数相同故我们可以公用空间)

\(dp_i=dp_{i-1}+10^{i-1}\),理解??
比如从一位到两位:
\(1.\)\(0\)~\(9\)在第一位各出现一次,到两位时它们前面补上\(0\)~\(9\)(第一位为0:00,10......90)故在\(dp_{i-1}\)基础上乘\(10\)
\(2.\)不仅要算原有位出现的次数,新加的该位也要算(第二位为1:10,11......19),数满\(i-1\)位,故加上\(10^{i-1}\)

当然你也可以手玩一遍验证一下

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL dp[20],tmp[20],a[20];
int main(){
    dp[0]=0,tmp[0]=1;
    for(LL i=1;i<=4;++i){
        dp[i]=dp[i-1]*10+tmp[i-1],
        tmp[i]=tmp[i-1]*10;
    }
    for(LL i=0;i<=9999;++i)
        for(LL j=1,bit=i;j<=4;++j)
            ++a[bit%10],
            bit/=10;
    printf("%lld",dp[4]);printf("\n");
    for(LL i=0;i<=9;++i)
        printf("%lld ",a[i]);printf("\n");
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/y2823774827y/p/10301145.html