CountingDigits projecteuler156题

Starting from zero the natural numbers are written down in base 10 like this: 
0 1 2 3 4 5 6 7 8 9 10 11 12....

Consider the digit d=1. After we write down each number n, we will update the number of ones that have occurred and call this number f(n,1). The first values for f(n,1), then, are as follows:

n

f(n,1)

0

0

1

1

2

1

3

1

4

1

5

1

6

1

7

1

8

1

9

1

10

2

11

4

12

5

Note that f(n,1) never equals 3. 
So the first two solutions of the equation f(n,1)=n are n=0 and n=1. The next solution is n=199981.

In the same manner the function f(n,d) gives the total number of digits d that have been written down after the number n has been written. 
In fact, for every digit d ≠ 0, 0 is the first solution of the equation f(n,d)=n.

Let s(d) be the sum of all the solutions for which f(n,d)=n
You are given that s(1)=22786974071.

Find ∑ s(d) for 1 ≤ d ≤ 9.

Note: if, for some nf(n,d)=n for more than one value of d this value of n is counted again for every value of d for which f(n,d)=n.

 

题目意思就是一下两个:

f(n,d)代表0n这些数中d这个字符出现的次数和;

然后最后求所有满足 f(n,d)=nn的和。

 

 

这题我完成了前面求f(n,d)的代码,具体思路是这样的:

我观察到对于n9,99,999,9999这种最大的多位数时,不难想出19字符出现的次数是一样的,所以这里我先设一个函数sum,其中sum(x)代表当nx位数的最大值时,求0n所有字符的个数和;sum(x,y)代表这些的其实就是当nx位数的最大值时,求0n出现的y字符的个数和,例如sum(1,1)=f(9,1)=1;我们可得当y的值为19时,sum(x,y)=[sum(x)-sum(x,0)]/9

首先对sum(x)进行求解:

由于是求0n所有字符的个数,所以是一位数的10个字符,加二位数的个数乘以2个字符,再加三位数的个数乘以3个字符······加到x位数的个数乘以x个字符:

sum(x)=10+90*2+900*3+…+9*10^(x-1)*x

接着我们对sum(x0)进行求解:

    这里我们设一个函数g(x),它代表x位数中字符0的个数,这里可以先求g(x)的通项,我发现g(x)g(x-1)有关:

1.  x位数的前x-1位中出现的0字符的个数为g(x-1)*10,例如2位数中的200,在三位数中出现了200201202...209这么10次;

2.  x位数的最后一位中出现0字符的个数为(x-1)位数的个数,因为就是相当于在它们后面加个0而已;

这时我们已经出现了g(x)与前一项的推导公式:

g(x)=g(x-1)*10+9*10^(x-2)

这里出现了一个很神奇的巧合就是个g(2)=9,为102030...909个,这有什么用呢?就是它符合g(x)=9*10^(x-2)*(x-1)这个公式,然后它使得g(x)的通项及其简单,这里用数学归纳法证明:

k满足g(k)=9*10^(k-2)*(k-1)时:

g(k+1)= 9*10^(k-2)*(k-1)*10+9*10^((k+1)-2)

              化简得:

g(k+1)= 9*10^((k+1)-2)*((k+1)-1)

       同时也符合g(x)=9*10^(x-2)*(x-1),得证当x>1时,g(x)=9*10^(x-2)*(x-1)。那么sum(x0)= g(1)+g(2)+...+g(x):

sum(x,0)=1+9+90*2+900*3+…+9*10^(x-2)*(x-1)

这里我们不难发现sum(x,0)=sum(x-1),那么可得当y的值为19时:

 sum(x,y)=[sum(x)-sum(x,0)]/9

=[sum(x)-sum(x-1)]/9

=9*10^(x-1)*x/9

=x*10^(x-1)

    意思就是说f(9,d)=1,f(99,d)=20,f(999,d)=300......,有了这个特性f(n,d)就好求了:

    首先获得nd,确认n有多少位,假设获得的n35642

获得n的第一位数,是3,那么它经历了099991999929999这三个阶段,共增加了sum(4,y)*3这么多个d字符;这个时候注意一下,如果d1或者2,那么会增加多10000d字符,因为我们算的只是后面4位数出现的d字符;至此029999出现的d字符已经统计完毕。

接着获得n第二位数,重复以上步骤,不过有需要注意的是,当d3的时候,会多增加5642d字符,因为我们算法后面算的是05642中出现的3字符,但是我们实际要算的是3000035642中出现的三字符;

····

直到获得最后一位,输出统计的d字符个数。

以下是我用Java实现的代码:

import java.util.Scanner;
 
public classCountingDigits {
 
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner sc=new Scanner(System.in);
        int i,j,d,m;
        long n,res=0,a[];
        String s,t;
        n=sc.nextLong();//获得n
        d=sc.nextInt();//获得d
        s=n+"";
        m=s.length();//获得n的位数
        a=new long[m-1];//新建一个m-1的数组,里面存放sum(x,y)的值
        for(i=0;i<</span>m-1;i++)
        {
            a[i]= (long) ((i+1)*Math.pow(10,i));
        }
        for(i=0;i<</span>m-1;i++)//开始实现第一位到倒数第二位的循环
        {
            for(j=0;jparseInt((String) s.subSequence(i,i+1));j++)
            {
                res=res+a[m-2-i];
                if(j==d)res=(long) (res+Math.pow(10,m-1-i));
            }
            if(j==d)res=res+Integer.parseInt((String) s.subSequence(i+1,m))+1;
        }
        for(j=0;jparseInt((String) s.subSequence(i,i+1))+1;j++)
        {
            if(j==d)res=(long) (res+Math.pow(10,m-1-i));
        }
        System.out.println(res);
    }
}

    至此已经求除了求f(n,d)的程序,我想的是对于这道题的问题找个上限由0找到它吧所有f(n,d)=n的情况记录下来求和,可是运算量太大我觉得是有更好的办法,以后想到的话更新····

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值