hdu-2089 不要62 基础DP 模板

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

数位DP的思想时预处理以x开头长度为len的数(例如 x000~x999)的所有情况。给出一个数,可以在log10(n)的复杂度下完成分解。

#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <cstdio>
#include <algorithm>
#define LL long long
using namespace std;
const LL N = 1000015;
const LL INF = 100000009;
LL dp[8][10];//bit,num
void init()
{
    memset(dp, 0, sizeof dp);//初始化为0
    LL sum = 0, temp = 0;//用sum维护上一层的总和,当传递不是简单的和传递时考虑用多维sum维护或者暴力
    for (int i = 0; i < 10; i++)
        dp[0][i] = 1;
    dp[0][4] = 0;
    sum = 9;
    for (int len = 1; len < 8; len++)
    {
        temp = 0;//临时记录本层
        for (int i = 0; i < 10; i++)
        {
            if (i == 4)continue;
            dp[len][i] = sum;
            if (i == 6) dp[len][i] -= dp[len - 1][2];
            temp += dp[len][i];
        }
        sum = temp;
    }
}
LL arr[100];//当前求解的数的分解
LL dfs(LL pos, LL pre)
{
    if (pos == -1)return 0;//尾部
    LL num = arr[pos];//获取当前数
    LL cnt = 0;//计算以pre为前缀,后面从0~num-1开头的所有情况
    for (int i = 0; i < num; i++)
    {
        if (pre == 6 && i == 2)continue;
        if (i == 4)continue;
        cnt += dp[pos][i];
    }
    if (num == 4)return cnt;
    if (pre == 6 && num == 2)return cnt;
    return cnt + dfs(pos - 1, num);//下一级dfs传递前缀(对于不同题目需要传递的前缀信息不同)
}
LL sol(LL x)
{
    x++;//dfs在求解时,只能解出x-1的所有情况,x需要在递归尾部特判,干脆我们将x++,这样正好求出x
    if (x == 0) return 1;
    LL siz = 0;
    while (x)
        arr[siz++] = x % 10, x /= 10;
    LL ans = 0;
    ans = dfs(siz - 1, -1);
    return ans;
}
int main() {
    cin.sync_with_stdio(false);
    LL n, m;
    init();
    while (cin >> n >> m)
    {
        if (n == 0 && m == 0) break;
        cout << sol(m) - sol(n - 1) << endl;
    }
    return 0;
}

 

posted @ 2017-09-07 16:02  Luke_Ye  阅读(233)  评论(0编辑  收藏  举报