版权声明:因为我是蒟蒻,所以请大佬和神犇们不要转载(有坑)的文章,并指出问题,谢谢 https://blog.csdn.net/Deep_Kevin/article/details/83002946
正题
这题看上去就像数位Dp.
对于每一个数,我们进行数位Dp。
还是类似于差分,用y的答案减去x-1的答案就可以了。
对于每个子问题,我们求解,用tf来记录前面是否“满”,用all记录前面是否都是0.
如果前面满了,我们枚举的end就是当前这一位的值,否则就是9.
如果这一位以及前面有不是0的位,那么这一位就有可能能取到答案,前面以及这一位满了,那么就是后一位的权值+1,否则就可以取10的幂次方。
这样每次Dp都记忆化一下就可以了。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
long long x,y;
long long solve[100];
long long val[100];
long long ci[100];
long long g[100];
long long Dp(int pos,int tf,int k,int all){
if(pos==0) return 0;
if(!tf && !all && solve[pos]!=-1) return solve[pos];
long long res=0;
int end=tf?val[pos]:9;
for(int i=0;i<=end;i++) {
res+=Dp(pos-1,tf&&i==end,k,all&&i==0);
if(!(all && i==0) && i==k) res+=((i==end&&tf)?g[pos-1]+1:ci[pos-1]);
}
if(!all && !tf) solve[pos]=res;
return res;
}
long long gett(long long v,int k){
memset(solve,-1,sizeof(solve));
int len=0;
while(v!=0){
val[++len]=v%10;
v/=10;
g[len]=g[len-1]+val[len]*ci[len-1];
}
return Dp(len,1,k,1);
}
int main(){
ci[0]=1;
for(int i=1;i<=15;i++) ci[i]=ci[i-1]*10;
long long tot=0;
scanf("%lld %lld",&x,&y);
x--;
for(int i=0;i<=9;i++)
printf("%lld ",gett(y,i)-gett(x,i));
}