数位dp的板子题?
显然\([a,b]\)等价于\([0,b]-[0,a]\)。
考虑\(dp_{i,j}\)表示到第\(i\)位数字\(j\)的答案。先不考虑数字大小限制(即1到999之类),则显然有
\(dp_{i,j}=dp_{i-1,j} \times10+10^{i-1}。当前数字是0时则减去10^{i-1},再减去1。\)
所以我们可以预处理出\(dp\),来表示后面这一坨。
实际操作的时候,我们可以不用写两维,写一维的cnt数组记录一下就可以。
再加上限制,当前数的方案数我们由小于等于它的最大999……9和剩余部分拼成。后面这一部分就是各位数字上的数乘\(dp_i\)之和。
比当前位小的数多出现了\(10^{i-1}\)次,加上。
当前位显然多出现了后面位组成的数字次。
然后前导零其实就是\(\sum_{i=1}^{len}10^i\),减去就行。
#include<bits/stdc++.h>
using namespace std;
long long a,b,l,r,num;
int numa[15],numb[15];
long long cnt[11];
long long f[15];
long long po[15]={1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000,10000000000,100000000000,100000000000,};
int main(){for(int i=1;i<=15;++i) f[i]=i*po[i-1];scanf("%lld %lld",&a,&b);if(a>b) swap(a,b);--a;while(a) numa[++l]=a%10,a/=10;while(b) numb[++r]=b%10,b/=10;for(int i=l;i>=1;--i){for(int j=0;j<=9;++j) cnt[j]-=numa[i]*f[i-1];for(int j=0;j<numa[i];++j) cnt[j]-=po[i-1];num=0;for(int j=i-1;j>=1;--j) num=num*10+numa[j];cnt[numa[i]]-=(num+1);cnt[0]+=po[i-1];}for(int i=r;i>=1;--i){for(int j=0;j<=9;++j) cnt[j]+=numb[i]*f[i-1];for(int j=0;j<numb[i];++j) cnt[j]+=po[i-1];num=0;for(int j=i-1;j>=1;--j) num=num*10+numb[j];cnt[numb[i]]+=(num+1);cnt[0]-=po[i-1];}for(int i=0;i<=9;++i) printf("%lld ",cnt[i]);return 0;
}