/*
数位dp,记忆化搜索,重要是边界
对于每一位有三种情况1.是1并且不是边界(123中1就是边界)。2,是1是边界。3,不是1
对于第一种情况,直接ans+power(len-1)即可,
第二种情况,直接加上剩余的必包含1,比如145,对于第一位1必定有100-145总共146个数必包含一个1
对于第三种情况不用考虑
当然中间状态要记录,记录的是不是边界的状态
*/
#include<stdio.h>
#include<string.h>
#define N 11
#define ll __int64
ll dp[N][N];
ll digit[N];
ll bit[N];
ll rest[N];
ll dfs(ll len,ll cnt,ll ok)
{
if(!len)
return 0;
if(!ok&&dp[len][cnt]!=-1)return dp[len][cnt];//不是边界,看是否记忆过
ll ans=0,i,maxx=ok?digit[len]:9;
for(i=0; i<=maxx; i++)
ans+=dfs(len-1,i,ok&&i==maxx);
if(maxx>1)//第一种状态
ans+=bit[len];
if(maxx==1)//第二种状态
ans+=rest[len-1];
if(!ok)//不是边界记忆
dp[len][cnt]=ans;
return ans;
}
ll f(ll n)
{
ll len=0,i;
rest[0]=1;
while(n)
{
digit[++len]=n%10;
rest[len]=n%10*bit[len]+rest[len-1];//处理剩余情况
n/=10;
}
/*for(i=1;i<=len;i++)
printf("%I64d\n",rest[i]);*/
return dfs(len,0,1);
}
int main()
{
ll n,i;
bit[1]=1;
for(i=2; i<=10; i++)
bit[i]=bit[i-1]*10;
memset(dp,-1,sizeof(dp));
while(scanf("%I64d",&n)!=EOF)
{
printf("%I64d\n",f(n)-f(0));
}
return 0;
}
NUBT1475 数位dp(记忆化搜索)
最新推荐文章于 2020-04-09 19:23:09 发布