hdu2089 数位dp

      第一次接触数位dp,对于这种题目,数字都是很大,直接遍历肯定超时,通过对每个位子上数字的遍历可以大大减小复杂度。

dp[i][j]表示1到 i位的以j开头的数有几个满足条件的。这样理解一下,然后求出目标n的位数和各个位上的值,遍历即可。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define INF 99999999
#define ll __int64
using namespace std;
const int MAXN = 10;
int dp[MAXN][MAXN];
void init()
{
    memset(dp,0,sizeof(dp));
    dp[0][0] = 1;
    int i,j,k;
    for(i=1; i<=9; i++){
        for(j=0; j<=9; j++){
            for(k=0; k<=9; k++){
                if(j!=4 && !(j==6 && k==2)){
                    dp[i][j] += dp[i-1][k];
                }
            }
        }
    }
}
int slove(int n)
{
    int digit[10],i,j,k;
    memset(digit,0,sizeof(digit));
    int len = 0;
    int x = n;
    while(1){
        if(!x)break;
        digit[++len] = x%10;
        x/=10;
    }
    int ans = 0;
    for(i=len; i>=1; i--){
        for(j=0; j<digit[i]; j++){
            if(j!=4 && !(j==2 && digit[i+1]==6))
                ans += dp[i][j];    
        }
        if(digit[i]==4 || (digit[i]==2 && digit[i+1]==6))//第i位是4 或者已经出现62了,不合法直接断开。
            break;
    }
    return ans;
}
int main()
{
    int i,j,n,m;
    init();
    while(cin>>n>>m){
        if(!n && !m)break;
        cout<<slove(m+1)-slove(n)<<endl;//[0,m]-[0,n)
    }
    return 0;
}
原文地址:https://www.cnblogs.com/sweat123/p/5113186.html