题目描述
科协里最近很流行数字游戏。某人命名了一种不降数,这种数字必须满足从左到右个位数字呈现小于等于的关系,如123,446.现在大家决定玩一个游戏,指定一个整数闭区间[a,b],问这个区间内有多少个不降数。
输入
输入多组测试数据。每组只包含两个数字a和b(1<=a,b<=2^31)
输出
每行给出一个测试数据的答案,即[a,b]之间有多少不降数。
样例输入
1 9 1 19
样例输出
9 18
题解
首先因为数位DP相较于其他DP来说更加模板化,所以主要是掌握和理解一下通用的模板之后,做题就会相对容易一些。这题的约束条件是低位数永远大于高位数,所以只要控制当i<pre时continue即可。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
long long int n,m;
int a[20],dp[20][10];//a用来存放数字的每位数
int dfs(int pos,int pre,bool limit)//pre表示pos位数的下一位数的值,例如pos=3表示当前位为百位,则pre表示十位数的值
{
if(pos==0)
return 1;
if(!limit&&dp[pos][pre]!=-1)
return dp[pos][pre];
int ans=0;
int up=limit?a[pos]:9;
for(int i=0;i<=up;i++)
{
if(i<pre)
continue;
ans+=dfs(pos-1,i,i==a[pos]&&limit);//从数字的高位向低位递归,新limit的取值根据原limit和i的取值决定,例如246,当pos表示十位数时,如果原limit=1(百位数=2)并且十位数等于4,那么下一次的搜索就会有限制(个位数上界限制为6)
}
if(!limit)
dp[pos][pre]=ans;
return ans;
}
int solve(int x)
{
int pos=0;//pos用于记录当前位数
while(x)
{
a[++pos]=x%10;//pos从1开始表示位数从个位到高位
x/=10;//如246在数组中的存放方式是6 4 2
}
return dfs(pos,0,1);//从数字的最高位开始
}
int main()
{
while(cin>>n>>m)
{
memset(dp,-1,sizeof(dp));
cout<<solve(m)-solve(n-1)<<endl;//减的是n-1不是n,n自身要算进去
}
return 0;
}