问题
分析
统计1-a,1-b的中的数字个数,然后相减
数位dp
//数位dp
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <vector>
#include <utility>
using namespace std;
typedef long long ll;
const int maxn=15;
ll le,ri,Ans[2][maxn],a[maxn],num[maxn],cnt[maxn],head[maxn];
//以54321为例
void solve(ll x,ll *ans){
int len=0,x2=x;
while(x){
a[++len]=x%10;
x=x/10;
}
num[1]=a[1];
for(int i=2;i<=len;++i){
num[i]=a[i]*head[i]+num[i-1];
}
//统计有前导0的i位数 i<len 0-9999
ans[0]=1;
for(int i=1;i<len;++i){
ans[0]+=9*cnt[i-1];
for(int j=1;j<10;++j){
ans[j]+=head[i]+9*cnt[i-1];
}
}
//统计没有前导0的,且i<a[len]的数 1000-49999
for(int i=1;i<a[len];++i){
ans[i]+=head[len];
}
for(int j=0;j<10;++j){
ans[j]+=(a[len]-1)*cnt[len-1];
}
if(x2!=0) ans[a[len]]+=(num[len-1]+1);
//50000-54321中的0000-4321
for(int i=len-1;i>0;--i){
for(int j=0;j<a[i];++j){
ans[j]+=head[i];
}
for(int j=0;j<10;++j) ans[j]+=a[i]*cnt[i-1];
ans[a[i]]+=(num[i-1]+1);
}
}
int main(void){
head[1]=1;
cnt[1]=1;
for(int i=2;i<maxn;++i){
head[i]=10*head[i-1]; //首部非0的i位数有多少个
cnt[i]=i*head[i]; //首部非0的i+1位数去除第一个数字剩下i的数字(无限制)的出现次数
}
while(scanf("%lld%lld",&le,&ri)==2 && (le || ri)){
memset(Ans,0,sizeof(Ans));
if(le>ri) swap(le,ri);
solve(ri,Ans[0]);
solve(le-1,Ans[1]);
for(int i=0;i<10;++i){
if(i) printf(" ");
printf("%lld",Ans[0][i]-Ans[1][i]);
}
printf("\n");
}
return 0;
}
//数位dp
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <vector>
#include <utility>
using namespace std;
typedef long long ll;
const int maxn=10;
struct Digits{
ll d[10],cur;
Digits(){
cur=0;
memset(d,0,sizeof(d));
}
Digits(ll cur){
this->cur=cur;
memset(d,0,sizeof(d));
}
Digits operator + (const Digits &rhs){
Digits temp;
for(int i=0;i<10;++i){
temp.d[i]=d[i]+rhs.d[i];
}
temp.cur=cur+rhs.cur;
return temp;
}
Digits& operator += (const Digits &rhs){
for(int i=0;i<10;++i){
d[i]+=rhs.d[i];
}
cur+=rhs.cur;
return *this;
}
};
ll le,ri;
// dp[pos][lead]是位数是pos,前导是lead,并且不是lim的状态,存储pos以后位的数字数量
int ans[maxn],a[maxn],vis[maxn][2];
Digits dp[maxn][2];
//pos是现在的位置,lead是是否有前导0,lim是代表数位的取值是否有上界
Digits dfs(int pos,int lead,bool lim){
if(pos==0) return Digits(1); //现在pos位的数字
if(!lim && dp[pos][lead].cur) return dp[pos][lead];
int up=(lim)?a[pos]:9;
Digits temp;
for(int i=0;i<=up;++i){
Digits t=dfs(pos-1,lead&&(i==0),lim&&(i==up));
temp+=t;
if(!lead || (lead&&i)) temp.d[i]+=t.cur; //pos位数字数,非前导0
}
if(!lim) dp[pos][lead]=temp;
return temp;
}
void solve(ll x,int d){
for(int i=0;i<maxn;++i){
for(int j=0;j<2;++j) dp[i][j].cur=0;
}
int pos=0;
while(x){
a[++pos]=x%10;
x=x/10;
}
Digits t=dfs(pos,1,true);
for(int i=0;i<10;++i) ans[i]+=d*t.d[i];
}
int main(void){
while(scanf("%lld%lld",&le,&ri)==2 && (le || ri)){
memset(ans,0,sizeof(ans));
if(le>ri) swap(le,ri);
solve(ri,1);
solve(le-1,-1);
for(int i=0;i<10;++i){
if(i) printf(" ");
printf("%lld",ans[i]);
}
printf("\n");
}
return 0;
}