数位 DP

【概述】

数位 DP 实际是一种计数用的 DP,一般就是统计一个区间 [le,ri] 内满足一些条件数的个数。

所求的限定条件往往与数的位数有关,例如:数位之和、指定数码个数、数的大小顺序分组等。

题目所给的区间范围往往很大,无法通过暴力枚举来求解,一般是要求把某个区间的符合某种特征的数的个数求出来,因此根据根据 “逐位确定” 的基本思想,将最大数按位分解,然后 dfs 依次判断每一位相应的数是否满足要求。 

【基本思想】

数位 DP 的实质就是一种暴力枚举的方式,使得新的枚举方式满足 DP 的性质,然后进行记忆化搜索。

对于一个求区间 [le,ri] 满足条件数的个数,最简单的暴力方式为:

for(int i=le;i<=ri;i++)
    if(right(i))
        ans++;

但这样枚举没有任何状态,不便于进行记忆化,因此,可以控制上界,从最高位向下枚举。

例如:要求比 456 小的数,可以如下考虑

4          5             6

4         5           (0~6)

4        (0~4)         (0~9)

(0~3)    (0~9)         (0~9)

此时,这种新的枚举只控制了上界,统计 [1,ri] 和 [1,le-1] 的数量,然后相减即为区间 [le,ri] 的数量,需要注意的是 le 的范围都是大于等于 1 的

int main()
{
    long long le,ri;
    while(~scanf("%lld%lld",&le,&ri))
        printf("%lld\n",solve(ri)-solve(le-1));
}

【模板】

枚举到当前位置 pos,状态为 state 的数量,dp 值保存的是满足条件数的个数。

typedef long long LL;
using namespace std;
int a[20];
LL dp[20][state];//不同题目状态不同
/*
    pos 枚举到当前位置
    lead 前导零,不是每个题都要判断
    limit 数位上界变量
*/
LL dfs(int pos,state变量,bool lead,bool limit)
{
    /*
        递归边界,由于按位枚举,最低位是0,此时说明枚举完了
        此时一般返回1,表示枚举的这个数是合法的,
        因此要保证枚举时每一位都要满足题目条件,
        即当前枚举到pos位,
    */
    if(pos==-1)
        return 1;

    if(!limit && !lead && dp[pos][state]!=-1) //记忆化
        return dp[pos][state];

    int up=limit?a[pos]:9;//根据 limit 判断枚举的上界

    LL ans=0;
    for(int i=0;i<=up;i++)//枚举
    {
        /*把不同情况的个数加到ans*/
        if()
            ...
        else if()
            ...
        else
            ...

        ans+=dfs(pos-1,状态转移,lead && i==0,limit && i==a[pos])
    }

    if(!limit && !lead)//计算完,记录状态
        dp[pos][state]=ans;
    return ans;
}
LL solve(LL x)
{
    int pos=0;
    while(x)//分解数位
    {
        a[pos++]=x%10;//存储各数位
        x/=10;
    }
    return dfs(pos-1,一系列状态,true,true);//从最高位开始枚举
}
int main()
{
    LL le,ri;
    while(~scanf("%lld%lld",&le,&ri))
    {
        memset(dp,-1,sizeof(dp));//一般初始化为-1
        printf("%lld\n",solve(ri)-solve(le-1));
    }
}

【例题】

  1. 不要62(HDU-2089):点击这里
  2. Bomb(HDU-3555):点击这里
  3. B-number(HDU-3652):点击这里
  4. Balanced Number(HDU-3709):点击这里
  5. F(x)(HDU-4734):点击这里

猜你喜欢

转载自blog.csdn.net/u011815404/article/details/82387955
今日推荐