题目链接
思路
数位DP,DP存储三个东西,当前在第几位pos,什么数字,上升还是下降状态。
dfs传pos当前位置
limit是否存在上界
pre是否有前导0
flag 0表示下降,1表示上升
last表示上一个值
last初始值-1,记忆化加速额外判断下last是否为-1
递归区域分三种情况,存在前导0且当前是0,有前导0且当前非0,无前导0
代码
#include <stdio.h>
#include <string.h>
#define ll long long
const ll mod = 1e9+7;
char s[105];
ll a[105], dp[105][15][2];
ll dfs(ll pos, ll limit, ll pre, ll flag, ll last)
{
if(pos == -1) return !pre;
ll up = limit ? a[pos] : 9;
if(!limit && last != -1 && dp[pos][last][flag] != -1) return dp[pos][last][flag];
ll tmp = 0;
for(ll i = 0; i <= up; ++i)
{
if(flag == 1 && i < last) continue;
if(pre && i == 0) tmp += dfs(pos-1,limit&&i==up,1,0,-1);
else if(pre) tmp += dfs(pos-1,limit&&i==up,0,0,i);
else tmp += dfs(pos-1,limit&&i==up,0,(flag == 0 ? i > last : 1), i);
tmp %= mod;
}
if(!limit && last != -1) dp[pos][last][flag] = tmp;
return tmp;
}
int main()
{
ll t;
memset(dp,-1,sizeof(dp));
for(scanf("%lld",&t); t; --t)
{
scanf("%s",s);
ll len = strlen(s);
for(ll i = 0; i < len; ++i) a[len-i-1] = s[i]&15;
printf("%lld\n",dfs(len-1,1,1,0,-1));
}
return 0;
}