zoukankan      html  css  js  c++  java
  • 统计数字问题 算法实现1-1

    统计数字问题 算法实现1-1

    题意

    题目来自《计算机算法设计与分析(第五版)》第七页。

    一本书的页码从自然数开始顺序编码直到自然数n。

    求这n个数中,使用了数字0 1 2...9各使用了多少次。

    解题思路

    暴力算法

    使用for循环,每个数分别进行处理。

    //核心代码如下
    for(int i=1; i<=n; i++){
        int tmp = i;
        while(tmp){
            c[tmp%10]++;
            tmp /= 10;
        }
    }
    

    递归的方式

    在《算法设计与分析》这个书的课后题解中提到了一个公式,如下:

    从0到9组成的n位数字,一个有$$10^n$$个数(注意,这些数都是n位,因此0的表达:n个0)。这些数字中0 1 ... 9每个数字使用的次数相同,设为$$f(n)$$。那么该函数满足如下的递归式:

    [f(n)=egin{cases} 10f(n)+10^{n-1} & n>1 \ 0 & n=1 end{cases} ]

    化为非递归的形式为:$$f(n)=n10^{n-1}$$

    这是递归的基础。因为有前导零,所以后续还需要进一步处理。

    比如n=3210,数的位数 = len

    那么我们最容易处理的是000 到999,这里数字的使用个数,假设为k。然后因为最高位可以选0 1 2,设有p(p=3)个数(3这里不选的原因是,这里的范围仅仅到3210,没有到3999),所以0000 到2999数字的使用个数就可以具体得到,如1的使用个数就是

    [c[1]=p*k + 10^{len-1} ]

    其他的类似。

    接下来处理前导0的情况:

    for(int i=0; i<len; i++)//i代表位数-1,i=0时处理的是个位上的数值0,一共一个。
        c[0] -= (int)pow(10.0, i);
    //注意题目数说数字是从1开始的
    

    到现在我们已经处理完了0000到2999这些数字。

    剩下还有3000到3210

    这里使用直接让记录最高位数字的数组+1+t(t的定义在下面),然后我们就可以处理去掉最高位的数字了。

    [t=n\%(10^{len-1})$$,这里t=210 然后这里的t有两种情况: 1. 如果t=0,比如n=200时,那么c[0] += len - 1,也就是加2 如果n=10,那么t=0,着从c[0]+=len-1,也就是加1 这样这个程序就可以结束了,不在递归了。 2. 如果t不等于0,那么需要判断一下$$len(t)!=len-1$$的情况。比如n=10010,t=10,那么中间的0也需要处理一下,$$c[0]+=(len-1-len(t))*(t+1)$$。然后再次调用这个函数即可。 需要注意的问题是输出的精度问题,因为函数`pow(a,b)`有时候输出的精度不准确,使用`round(x)`来进行处理(因为我们需要的是一个整数)。 ## 代码实现 ``` cpp #include<iostream> #include<cstdio> #include<cmath> using namespace std; int c[10]; void solve(int n){ //数n的位数 int len=log10(n)+1; //最高位的值 int p=n/((int)round(pow(10.0,len-1))); for(int i=0;i<10;i++){ c[i]+=p*(len-1)*(int)round(pow(10.0,len-2)); } //每个数最高位去定一个数时,剩下位数有10^(len-1)不同的数。 for(int i=0;i<p;i++){ c[i]+=(int)round(pow(10.0,len-1)); } //获得去掉最高位的数 int t=n % (int)round(pow(10.0,len-1)); c[p]+=1+t;//最高位需要添加 if(t==0){//如果t为0 c[0]+=len-1;//0位加len-1 return ; } int lenT=log10(t)+1; if(lenT!=len-1){//若像10010这种情况,中间2个0也要相应的处理 c[0]+=(len-lenT-1)*(t+1); } return solve(t); } int main(){ int n; while(cin>>n){ fill(c,c+10,0); int len=log10(n)+1; solve(n); for(int i=0;i<len;i++){ c[0]-=(int)round(pow(10.0,i)); } for(int i=0;i<10;i++){ cout<<i<<" : "<<c[i]<<endl; } } } ``` ## 参考资料 https://blog.csdn.net/m0_37579232/article/details/79651307]

  • 相关阅读:
    hdu 2019 数列有序!
    hdu 2023 求平均成绩
    HDU 5805 NanoApe Loves Sequence (思维题) BestCoder Round #86 1002
    51nod 1264 线段相交
    Gym 100801A Alex Origami Squares (求正方形边长)
    HDU 5512 Pagodas (gcd)
    HDU 5510 Bazinga (字符串匹配)
    UVALive 7269 Snake Carpet (构造)
    UVALive 7270 Osu! Master (阅读理解题)
    UVALive 7267 Mysterious Antiques in Sackler Museum (判断长方形)
  • 原文地址:https://www.cnblogs.com/alking1001/p/13346212.html
Copyright © 2011-2022 走看看