題目描述
給定兩個正整數a和b,求在[a,b]中的所有整數中,每個數碼各出現了多少次。
題目分析
膜膜膜PoPoQQQ大爺。
首先,我們可以把求[a,b]中間的數量改成[1,b]-[1,a-1]。
然後考慮怎麼求[1,x]。
首先,對於位數小於x的數字因爲每位數可以隨便取,所以每一個數字出現次數是一樣的(允許前導0)。我們不妨預處理
現在考慮位數和x相同時怎麼做,我們還是從高到低枚舉每一位數,不妨設當前數爲
然後就完了,唯一需要注意的是因爲枚舉每一位數時都沒有計算上限值,所以答案求出來是
代碼
/**************************************************************
Problem: 1833
User: szpszp
Language: C++
Result: Accepted
Time:4 ms
Memory:1292 kb
****************************************************************/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define MAXN
#define MAXM
#define INF 0x3f3f3f3f
typedef long long int LL;
template<class T>
void Read(T &x){
x=0;char c=getchar();bool flag=0;
while(c<'0'||'9'<c){if(c=='-')flag=1;c=getchar();}
while('0'<=c&&c<='9'){x=x*10+c-'0';c=getchar();}
if(flag)x=-x;
}
LL g[20],powten[20];
int num[15];
int len;
void getnum(LL x){
len=0;
while(x)num[++len]=x%10,x/=10;
}
LL ans[10];
void Solve(LL x,LL flag){
getnum(x);
for(int i=1;i<len;++i){
ans[0]+=g[i-1]*9*flag;//0不能放在末尾
for(int j=1;j<10;++j)
ans[j]+=(g[i-1]*9+powten[i-1])*flag;
}
LL now=powten[len-1],t=now;
int pos=len-1;
while(now<x){
while(now+t<=x){
LL tmp=now/t;
while(tmp)ans[tmp%10]+=t*flag,tmp/=10;
for(int i=0;i<10;++i)ans[i]+=g[pos]*flag;
now+=t;
}
t/=10,--pos;
}
}
void init(){
memset(ans,0,sizeof(ans));
g[0]=0,powten[0]=1;
for(LL i=1;i<15;++i){
powten[i]=powten[i-1]*10;
g[i]=g[i-1]*10+powten[i-1];
}
}
int main(){
init();
LL l,r;
Read(l),Read(r);
Solve(r+1,1);
Solve(l,-1);
for(int i=0;i<9;++i)
printf("%lld ",ans[i]);
printf("%lld\n",ans[9]);
}