可以用数学方法去递归,也可以用DP。最后情况是:
数学:30行代码,94MS;
DP:69行代码,63MS;
数学递归cpp:
#include<cstring>
#include<cstdio>
using namespace std;
void cac(long long con,long long &cnt,long long t)
{
if(con<=0)
return;
long long x,y,n=con/10;
long long i,j;
x=con/10,y=con%10;
for(;x!=0;x/=10)
if(x%10==0)
cnt+=(y+1)*t;
cnt+=n*t;
cac(n-1,cnt,t*10);
}
int main()
{
long long m,n;
while(scanf("%lld%lld",&m,&n),m>=0)
{
long long sum1=0,sum2=0;
cac(m-1,sum1,1ll);
cac(n,sum2,1ll);
if(m==0)
sum2++;
printf("%lld\n",sum2-sum1);
}
return 0;
}
DP:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long dp[2][15][15];
long long ten[15];
long long dfs(long long n)
{
if(n<0)
return 0;
else if(n==0)
return 1;
long long a[15],len,nn=n;
for(len=0;n;len++)
{
a[len]=n%10ll;
n/=10ll;
}
reverse(a,a+len);
long long ans=0,tp=a[0]-1ll;
if(tp!=0)
for(long long i=1;i<=len-1;i++)
ans+=tp*dp[0][len-1][i]*i;
for(long long i=1;i<=len-1;i++)
for(long long j=1;j<i;j++)
ans+=dp[1][i][j]*j;
for(long long i=1;i<len;i++)
{
tp=a[i]-1ll;
if(tp>0ll)
{
for(long long j=1;j<=len-i-1;j++)
ans+=tp*dp[0][len-i-1][j]*j;
}
if(tp!=-1ll)
{
for(long long j=0;j<=len-i-1;j++)
ans+=dp[0][len-i-1][j]*(j+1ll);
}
else
ans+=nn%ten[len-i-1]+1ll;
}
return ans+1ll;
}
int main()
{
memset(dp,0,sizeof(dp));
dp[0][0][0]=1;
dp[0][1][1]=1;
dp[0][1][0]=9;
dp[1][1][0]=9;
ten[0]=1;
for(long long i=1;i<=13;i++)
ten[i]=ten[i-1]*10;
for(long long i=2;i<=13;i++)
{
for(long long j=0;j<i;j++)
dp[1][i][j]=dp[0][i-1][j]*9;
dp[0][i][0]=9*dp[0][i-1][0];
for(long long j=1;j<=i;j++)
dp[0][i][j]=dp[0][i-1][j-1]+9*dp[0][i-1][j];
}
long long n,m;
while(scanf("%lld%lld",&m,&n)&&m>=0)
{
printf("%lld\n",dfs(n)-dfs(m-1));
}
return 0;
}