题目描述
给定两个正整数 a 和 b,求在 [a,b]中的所有整数中,每个数码(digit)各出现了多少次。
输入格式
仅包含一行两个整数 a,b含义如上所述。
输出格式
包含一行十个整数,分别表示 0∼9 在 [a,b] 中出现了多少次。
输入输出样例
输入
1 99
输出
9 20 20 20 20 20 20 20 20 20
说明/提示
数据规模与约定
- 对于 30% 的数据,保证 a≤b≤106;
- 对于 100% 的数据,保证 1≤a≤b≤1012。
思路
首先,这道题的常规做法应该是数位DP,但是本蒟蒻不会qwq。
- 要求 [a,b] 中0~9个出现了多少次,我们可以分别计算0 ~ 9各出现了多少次。
- a~b不好求,但是1 ~ a和1 ~ b还是比较好求的。
ans(l,r)=ans(1,r)-ans(1,l-1);//注意是l-1
- 于是问题就转化为了求在1~n中数字x出现了几次。
- 我们可以暴力枚举1~n,对每个数拆分判断。但是,这显然会超时。
- 所以我们可以考虑x在每一位各出现了多少次,然后加起来就是答案。
- 对x在每一位出现的次数的计算,不好描述。
- 具体看代码。
代码
#include<cstdio>
#define int long long
inline int read(){
int x=0;char c=getchar();
while(c>'9'||c<'0') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();
return x;
}
int js(int n,int x){
int s=0,i=1,l=n,m,r;//l是左边的数 m是中间的数 r是右边的数
//例如51476 当m=6时 l=5147,r无意义
// 当m=7时 l=514,r=6
// 当m=4时 l=52,r=76
// 当m=1时 l=5,r=476
// 当m=5时 l无意义,r=1476
while(l)
{
l/=10,m=n/i%10,r=n%i;//计算l,m,r
if(x)//x不为0时
{
if(m>x) s+=(l+1)*i;//m>x时 只需计算左边的
if(m==x) s+=l*i+r+1;//m=x时 左边的和右边的
if(m<x) s+=l*i;//m<x时 左边的
}
else//x=时
if(m) s+=l*i;//m不为0即m>x
else s+=(l-1)*i+r+1;
/*精简版
s+=l*i;
if(m>x&&x) s+=i;
if(m==x&&x) s+=r+1;
if(!m&&!x) s+=-i+r+1;*/
i*=10;
}
return s;
}
signed main(){
int l=read(),r=read();
for(int x=0;x<=9;++x)
printf("%lld ",js(r,x)-js(l-1,x));
return 0;
}