HDU - 2089 不要62(数位DP)

详细见https://blog.csdn.net/HowardEmily/article/details/54744573

题目:

 

思路:

数据量这么大遍历是不可能的,这道题其实是数位DP的经典题。

数位DP:

  数位:个、十、百、千等就是数位

  实质:暴力枚举加记忆化

  适用范围:在一段数的区间内找出满足某些条件的数的个数

此题思路:

  用二维数组dp[i][j],其中i表示位数,j表示首位数字

  得到状态转移方程:

 

 

详细见代码,但是值得注意的是:

 

 

因为求得的是小于n的数,所以求[0,n]之 间的数需要求n+ 1.

 

 

 

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
int dp[10][10];
void preprocess()//预处理dp[i][j] 即首位是j有i位数的数满足条件的个数 
{
    dp[0][0]=1;
    for (int i=1;i<=7;i++)
        for (int j=0;j<=9;j++)
        {
            if (j==4)                        
                continue;
            for (int k=0;k<=9;k++)
                if (!(j==6&&k==2))
                    dp[i][j]+=dp[i-1][k];
        }
}

int cal(int n)                //计算0~n之间有多少满足条件的数 
{
    int d[10],len=0;
    int ans=0;
    while (n)                 //所求的0~n之间满足条件的数一位位进行分离 
    {
        d[++len]=n%10;
        n/=10;
    }
    d[len+1]=0;
    for (int i=len;i;i--)  //进行状态转移 
    {
        for (int j=0;j<d[i];j++) 
            if (d[i+1]!=6||j!=2)
                ans+=dp[i][j];
        if (d[i]==4||(d[i+1]==6&&d[i]==2))
            break;
    }
    return ans;
}

void solve()
{
    int n,m;
    preprocess();
    while ((cin>>n)&&(cin>>m))
    {
        if (n==0&&m==0)
            return;
        cout<<(cal(m+1)-cal(n))<<endl;
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    solve();
    return 0;
} 

 

posted @ 2020-06-16 17:51  CimonHe  阅读(71)  评论(0)    收藏  举报