题意
不加描述啦qwq
题解
好像不太会写记忆化搜的,于是听取同学意见写了正常的dp。
然后这就是我第一次写不是记忆化的数位dp啦
用f[i][j][k][flag]表示前i位,前一位为j,是否抵上界的状态为flag,k数字出现的次数。
如果单单是这样子做的话会发现不行,因为你还不知道前一个状态有多少种这样的数字,所以还需要一个g[i][j][flag]表示前i位,前一位为j,是否抵上界状态为flag的数字个数。
就能用dp求得1~9的数字出现的次数,然后用总数字数减去1~9出现的次数就是0出现的次数啦qwq
//Suplex
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#define ll long long
using namespace std;
int digit[10000];
ll A,B,all,f[100][15][2],g[100][15][2],ans[15];
ll solve(ll x,int y)
{
if(!x) return 0;
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
int len=0;
while(x){
digit[++len]=x % 10;
x/=10;
}
for(int i=0;i<=digit[len];i++){
f[len][i][i==digit[len]]=(i==y);
g[len][i][i==digit[len]]=1;
}
for(int i=len-1;i;i--){
for(int j=0;j<=9;j++)
for(int k=0;k<=9;k++){
f[i][j][0]+=f[i+1][k][0]+g[i+1][k][0]*(j==y);
g[i][j][0]+=g[i+1][k][0];
}
for(int j=0;j<=digit[i];j++){
f[i][j][j==digit[i]]+=f[i+1][digit[i+1]][1]+(j==y);
g[i][j][j==digit[i]]++;
}
}
ll ans=f[1][digit[1]][1];
for(int i=0;i<=9;i++) ans+=f[1][i][0];
return ans;
}
ll query(ll x)
{
ll now=x,ans=0,pre=1;
int num=0;
while(now){
num++;now/=10;
}
for(int i=1;i<=num-1;i++){
ans+=((ll)i*(pre*10-pre));
pre*=10;
}
ans+=(x-pre+1)*num;
return ans;
}
int main()
{
scanf("%lld%lld",&A,&B);
for(int i=1;i<=9;i++) ans[i]=solve(B,i)-solve(A-1,i);
all=query(B)-query(A-1);
for(int i=1;i<=9;i++) all-=ans[i];
printf("%lld",all);
for(int i=1;i<=9;i++) printf(" %lld",ans[i]);
puts("");
return 0;
}