一本通1586:【 例 2】数字游戏
Description
Solution
数位dp裸题。
前缀和思想,\(ans_{a,b}\) 即为 \(ans_{1,b} - ans_{1,a-1}\)。
讲解都在代码里。
\(dp\) 过程用 \(dfs\) 来实现。
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int l, r;
int num[13],dp[13][13][2]; //dp[i][j][k]:第i位,上一位是数字j,k:是否有上限(都放到状态里,懒人写法)
inline int dfs(int len, int pre, int lim){ //len:当前处理到了第几位,pre:上一位是多少,lim:上一位是否取到最大值(是:这一位有上限。否:这一位可以取0~9)
if(!len) return 1;
if(dp[len][pre][lim] != -1) return dp[len][pre][lim]; //记忆化(注意判断!=-1)
int res = lim ? num[len] : 9; //lim有值:上限为num[len]。没值:上限为9
int ans = 0;
for(int i = 0; i <= res; i++)
if(i >= pre) ans += dfs(len - 1, i, lim && (i == res)); //lim的值手玩一下就知道了(前一位和当前位都是最大值时,lim为1)
return dp[len][pre][lim] = ans; //别忘了给dp赋值
}
inline int solve(int x){
int len = 0;
while(x){
num[++len] = x % 10; //把x拆开,注意这里是倒着存的,所以后面从len开始dfs
x /= 10;
}
memset(dp, -1, sizeof(dp));
return dfs(len, 0, 1);
}
int main(){
while(scanf("%d%d", &l, &r) != EOF)
printf("%d\n", solve(r) - solve(l - 1));
return 0;
}