传送门
【题目分析】
数位DP果然还是一如既往的恶心啊。。。。
按照题意统计10次就行了,要记录两个数组,一个是,这是无限制情况下的答案数,一个是
的前缀和,这是有限制的答案数。
记得拆数的时候cnt要清零。。。。。
【代码~】
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=13;
int cnt,num[MAXN];
LL l,r;
LL dp[MAXN];
LL sum1[MAXN],sum2[MAXN];
LL Read(){
LL i=0,f=1;
char c;
for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar());
if(c=='-')
f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())
i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
LL DP(LL pos,int numb,int lim,int zer){
if(!pos)
return 0;
if(!lim&&!zer&&dp[pos]!=-1)
return dp[pos];
int sx=lim?num[pos]:9;
LL ret=0;
for(int i=0;i<=sx;++i){
if(zer&&i==0)
ret+=DP(pos-1,numb,lim&(sx==i),1);
else{
if(i==numb){
if(i==sx&&lim)
ret+=sum2[pos-1]+1+DP(pos-1,numb,lim&(i==sx),0);
else
ret+=sum1[pos-1]+DP(pos-1,numb,lim&(i==sx),0);
}
else
ret+=DP(pos-1,numb,lim&(i==sx),0);
}
}
if(!lim&&!zer)
dp[pos]=ret;
return ret;
}
LL calc(LL x,int k){
memset(dp,-1,sizeof(dp));
cnt=0;
while(x){
num[++cnt]=x%10;
x/=10;
sum2[cnt]=sum2[cnt-1]+num[cnt]*sum1[cnt-1];
}
return DP(cnt,k,1,1);
}
int main(){
l=Read(),r=Read();
sum1[0]=1;
for(int i=1;i<=12;++i)
sum1[i]=sum1[i-1]*10;
for(int i=0;i<=9;++i)
cout<<calc(r,i)-calc(l-1,i)<<' ';
return 0;
}