http://acm.hdu.edu.cn/showproblem.php?pid=2089

基础的数位dp,当初不懂数位dp水过去的,今天重新写一下,解释看注释

预处理+递推

学自http://wenku.baidu.com/view/9de41d51168884868662d623.html

#include <iostream>
using namespace std  ;
int f[8][10] ;//f[i][j]表示第i位是数j时符合条件的数字数量 
int digit[9] ;//digit[i]表示n从右到左第i位是多少 
void Init()
{
    f[0][0]=1 ;
    for(int i=1 ;i<=7 ;i++)
    {
        for(int j=0 ;j<10 ;j++)//枚举第i位 
        {
            for(int k=0 ;k<10 ;k++)//枚举第i-1位
            {
                if(!(j==6 && k==2) && j!=4)//如果符合条件
                    f[i][j]+=f[i-1][k] ; 
            } 
        }
    }
}
int callen(int n)//计算n的长度 
{
    int cnt=0 ;
    while(n)
    {
        cnt++ ;
        n/=10 ;
    }
    return cnt ;
} 
void caldigit(int n,int len)//计算n的digit数组 
{
    memset(digit,0,sizeof(digit)) ;
    for(int i=1 ;i<=len ;i++)
    {
        digit[i]=n%10 ;
        n/=10 ;
    }
}
int solve(int n)//计算[0,n]区间满足条件的数字个数 
{
    int ans=0 ;
    int len=callen(n) ;
    caldigit(n,len) ;
    for(int i=len ;i>=1 ;i--)
    {
        for(int j=0 ;j<digit[i] ;j++)//枚举第i位取值 
        {
            if(!(j==2 && digit[i+1]==6) && j!=4)//第i位满足条件 
                ans+=f[i][j] ;
        }
        if(digit[i]==4 || (digit[i]==2 && digit[i+1]==6))//第i位已经不满足条件,则i位以后都不可能满足条件,结束循环 
            break ;
    }
    return ans ; 
}
int main()
{
    Init() ;
    int n,m ;
    while(~scanf("%d%d",&n,&m))
    {
        if(n==0 && m==0)
            break ;
        printf("%d\n",solve(m+1)-solve(n)) ;//用[0,m]-[0,n)即可得到区间[n,m] 
    }
    return 0 ;
}
View Code

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-02-21
猜你喜欢
  • 2021-09-26
  • 2021-12-12
  • 2021-11-27
  • 2021-12-13
  • 2021-05-15
  • 2021-06-14
相关资源
相似解决方案