P2602 数字计数


统计题

数字统计可以用一些特殊的方法来求

两位数的时候

例如:10~99 中 0,1,2,3,4,5,6,7,8,9 分别出现的次数

可以先看最高位有 $1$~$9$,$9$ 种选择,再看各位,$0$~$9$,$0$ 种选择,也就是说,只看十位 $1$x 有 $10$ 个 $1$,看个位 x$1$ 有 $9$ 个$1$。

$1$ 出现次数可以表达成 $1\times9+1\times10=19$ 和 $2$,$3$,$4$,$5$,$6$,$7$,$8$,$9$ 一样,但 $0$ 不一样,因为不能在最高位,所以出现的次数为 $1\times9=9$ 次

答案为:9,19,19,19,19,19,19,19,19,19

三位数的时候

例如:100~999 中 0,1,2,3,4,5,6,7,8,9 分别出现的次数

可以先看最高位有 $1$~$9$,$9$ 种选择,再看十位,$0$~$9$,$10$ 种选择,再看个位,$0$~$9$,$10$ 种选择,也就是说:

只看百位 $1$xx 有 $100$ 个 $1$,只看十位 x$1$x 有 $9\times10$ 个 $1$,只看个位 xx$1$ 有 $9\times10$ 个一。

$1$ 出现的次数可以表达成 $100+9\times10+9\times10=280$

$0$ 呢?$9\times10+9\times10=180$

四位数的时候(重点)

例如:1000~9999 中 0,1,2,3,4,5,6,7,8,9 分别出现的次数

可以先看最高位有 $1$~$9$,$9$ 种选择,再看百位,$0$~$9$,$10$ 种选择,再看十位,$0$~$9$,$10$ 种选择,再看个位,$0$~$9$,$10$种选择,也就是说,

只看千位 $1$xxx 有 $1000$ 个 $1$,只看百位 x$1$xx 有 $9\times10\times10$ 个 $1$,只看十位 xx$1$x 有 $9\times10\times10$ 个 $1$ ,只看个位 xxx$1$ 有 $9\times10\times10$ 个一。

$1$ 出现的次数可以表达成 $1000+9\times10\times10+9\times10*\times10+9\times10\times10=3700$

$0$ 呢?$9\times10\times10+9*10\times10+9\times10\times10=2700$

小结

是 $C^m_n$?但是:

例如:673~9283 中 0,1,2,3,4,5,6,7,8,9 分别出现的次数

进阶

通过仔细地观察,可以发现,可以将这些数拆分。
1673->1000+600+70+3
  
经过细致的观察,发现可以寻找一个中间量:2000,先求出 2000~9283 中分别的数,再求出 1673~2000 中各数的出现次数。

还要拆分: 9283->9000+200+80+3
变成了 2000~9283->2000~9000+9001~9283,9201->9280,9281->9283

1673->2000 就先对容易多了
不断拆分即可

最后

碰见位数不同的就可以 $0$ 补位!!!

传送门

代码

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<cstdio>
#include<cctype>
#include<queue>
#include<iostream>
#include<cstdio>
#include<vector>
#include<map>
using namespace std;
long long a,b,w_w[20],f[20],x[20],y[20];
void ji(long long x,long long *xy){
    long long num[20]={0};
    int len=0;
    while(x){
        num[++len]=x%10;
        x=x/10;
    } 
    for(int i=len;i>=1;i--){
        for(int j=0;j<=9;j++)
        xy[j]+=f[i-1]*num[i];
        for(int j=0;j<num[i];j++)
        xy[j]+=w_w[i-1];
        long long num2=0;
        for(int j=i-1;j>=1;j--){
            num2=num2*10+num[j];
        }
        xy[num[i]]+=num2+1;
        xy[0]-=w_w[i-1];
    } 
}
int main(){
    cin>>a>>b;
    w_w[0]=1;
    for(int i=1;i<=15;i++){
        f[i]=f[i-1]*10+w_w[i-1];
        w_w[i]=10*w_w[i-1];
    }
    ji(a-1,x);ji(b,y);
    for(int i=0;i<=9;i++)cout<<y[i]-x[i]<<" ";
    return 0;
}

文章作者: 王大神——A001
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 王大神——A001 !
  目录