数位dp——hdu2089不要62

刚开始接触数位dp,看其他的博客和教程也不是很懂,不过学习就是一个循序渐进的过程嘛๑乛◡乛๑

下面简单写写入门级的hdu2089不要62

中途找到一个比较好的ppt,我觉得讲的还是很清楚的了->初探数位dp

(下面的过程咋一看不明白可以把中间的过程打印出来,我是这样做的,感觉初学很见效)

1、预处理

dp[i][j]代表首位为j的i位数里符合条件(不含62和4)的数的个数

提前都算出来,在下一步可以直接用(数组开销也不大,本题中[7][10]足够了)

比如dp[3][0]代表的就是000~099之间符合条件的数,dp[3][1]代表100~199之间的数...

2、计算

统计区间[left,right]的个数可以看作[0,right]-[0,left)

可以设想把一个数分成不同范围的数的集合并集

比如321可以看作[0,99]+[100,199]+[200,299]+[0,9]+[10,19]+[0,1],即dp[3][0]+dp[3][1]+dp[3][2]+dp[2][0]+d[2][1]+dp[1][0]+dp[1][1]

用digit[i]表示从右到左第i位上的数

如果在循环的时候遇到4或者62则停止计算(循环是从高位到低位算的,4和62往后的低位都不用考虑了)

动手做做想的更快些(•‾̑⌣‾̑•)✧˖°

#include <iostream>
using namespace std;
int dp[10][10] = {0};
void init()  
{  
    int i,j,k;  
    for(i = 0; i <=9; ++i) dp[1][i] = 1;  
    dp[1][4] = 0;  
    for(i = 2; i <= 6; ++i)  
    {  
        for(j = 0; j <= 9; ++j)  
        {  
            if(j==4)continue;  
            for(k = 0; k <= 9; ++k)  
            {  
                if(k!=4&&!(j==6&&k==2)) dp[i][j] += dp[i-1][k];  
            }  
        }  
    }  
}  
/* 
void soutInit(){
    for(int i=0;i<=6;++i){
        for(int j=0;j<=9;++j){
            cout<<"dp["<<i<<"]["<<j<<"]="<<dp[i][j]<<endl;
        }
    }
}*/ 
int solve(int n)  
{  
    int i,j,k,digit[10];  
    int len = 0,ans = 0;  
    while(n!=0)  
    {  
        digit[++len] = n%10;  
        n/=10;  
    }  
    digit[len+1] = 0;  
    for(i = len; i > 0; --i)  
    {  
        for(j = 0; j < digit[i]; ++j)  
        {  
            if(j==4 || (digit[i+1]==6 && j == 2))continue;  
            ans += dp[i][j];  
            //cout<<"dp["<<i<<"]["<<j<<"]"<<" ";
        }  
        if(digit[i]==4||(digit[i]==2&&digit[i+1]==6))break;  
    }  
    return ans;  
}  

int main() {
    init();
    //soutInit();
    int l,r;
    while(cin>>l>>r){
        if(l==0&&r==0){
            break;
        }
        cout<<solve(r+1)-solve(l)<<endl;
    }
    return 0;
}

最后皮一下:

单说这道题的话,其实想过用字符串检测是否包含“62”或者“4”的,然后。。。TLE了(,,Ծ‸Ծ,,)

原文地址:https://www.cnblogs.com/zhaoGavin/p/8655936.html