hdu-2089 不要62 基础DP 模板

时间:2024-07-02 22:37:08

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