这算是一道数位DP的入门题了吧虽然对于我来讲仍是有点烦git
经典起手式不讲了吧,\(ans(a,b)\to ans(1,b)-ans(1,a-1)\)spa
咱们首先预处理一个东西,用\(f_i\)表示有\(i\)位数字的时候,每一个数字有几个(注意是和)。若不考虑前导零,则全部数字都是等价的,转移为:code
\(f_i=10\cdot f_{i-1}+10^{i-1}\)it
这个仍是比较好理解的吧,前面一项表示不管这一位放什么直接从前面拿过来已有的,因此这一位能够放\(0\to9\)十个数,后面一项表示当这一位放上想要的数字时和前面得出的贡献。io
咱们发现这样就很巧妙的避免了重复,由于先后两次计算恰好会产生屡次贡献。入门
而后考虑如何根据\(f_i\)推出答案。假设如今的数为\(ABCD\)class
和常规的数位DP同样,咱们优先考虑首位对答案的共献,因为\(1000,2000,...,A000\)都小于等于\(ABCD\),能够直接加入贡献,因此咱们将答案加上\(A\cdot f_3\)便可。static
而后就是剩下的\(A000\to ABCD\)部分了,可是咱们发现这个的求解过程就至关于\(BCD\)的贡献。di
因此咱们成功将大问题分解,接下来就是继续算下一位的贡献了while
最后还有一个关于前导零的问题了,咱们继续手玩一波
当首位为\(0\)时,后面的\(10^{i-1}\)位都是不合法的,以此类推,当前两位为\(0\)时,后面的\(10^{i-2}\)位也不合法。
所以\(0\)的贡献应该减去\(\sum_{i=0}^{len-1} 10^i\)(\(len\)表示数字位数)
而后可喜可贺,终于作完了,上CODE吧
#include<cstdio> #include<cctype> using namespace std; const int N=15; const long long pow[12]={1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000,10000000000,100000000000}; long long a,b,c[10],d[10],f[N]; int bit[N],cnt; inline char tc(void) { static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++; } inline void read(long long &x) { x=0; char ch; while (!isdigit(ch=tc())); while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc())); } inline void write(long long x) { if (x>9) write(x/10); putchar(x%10+'0'); } inline void init(void) { for (register int i=1;i<=12;++i) f[i]=f[i-1]*10+pow[i-1]; } inline void resolve(long long x) { cnt=0; while (x) bit[++cnt]=x%10,x/=10; } inline void solve(long long x,long long *num) { register int i,j; resolve(x); for (i=cnt;i>=1;--i) { for (j=0;j<bit[i];++j) num[j]+=pow[i-1]; for (j=0;j<=9;++j) num[j]+=f[i-1]*bit[i]; long long tot=0; for (j=i-1;j>=1;--j) tot=tot*10+bit[j]; num[bit[i]]+=tot+1; num[0]-=pow[i-1]; } } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); register int i; read(a); read(b); init(); solve(a-1,c); solve(b,d); for (i=0;i<=9;++i) write(d[i]-c[i]),putchar(' '); return 0; }