可以用数学方法去递归,也可以用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; }