在给定范围内使用特定数字写入的所有数字的总和

时间:2015-07-08 06:58:05

标签: algorithm math

我的目标是找到4到666554之间的所有数字的总和,仅包括4,5,6。

SUM = 4+5+6+44+45+46+54+55+56+64+65+66+.....................+666554.

简单的方法是运行循环并仅添加由4,5和6组成的数字。

long long sum = 0;
for(int i=4;i <=666554;i++){
   /*check if number contains only 4,5 and 6.
     if condition is true then add the number to the sum*/
}

但似乎效率低下。检查数字是由4,5和6组成需要时间。有没有办法提高效率。我已经尝试了很多,但没有找到新的方法。请帮助。

6 个答案:

答案 0 :(得分:46)

对于1位数字,请注意

4 + 5 + 6 == 5 * 3

对于2位数字:

(44 + 45 + 46) + (54 + 55 + 56) + (64 + 65 + 66)
== 45 * 3 + 55 * 3 + 65 * 3
== 55 * 9

等等。

一般情况下,对于n - 位数,其中有3个 n 仅由456组成,它们的平均值恰好是5...5n位数)。使用代码,它们的总和是('5' * n).to_i * 3 ** n(Ruby)或int('5' * n) * 3 ** n(Python)。

您最多可以计算6位数字,然后将666555的总和减去666666

P.S:对于像666554这样的小数字,使用模式匹配足够快。 (example

答案 1 :(得分:5)

在基数3(数字值的数量)中实施计数器,例如0,1,2,10,11,12,20,21,22,100 ....然后将基数为3的数字转换为数字4,5,6(0-> 4,1-&gt; ; 5,2-> 6),并添加到运行总计。重复直到限制。

def compute_sum(digits, max_val):

  def _next_val(cur_val):
    for pos in range(len(cur_val)):
      cur_val[pos]+=1
      if cur_val[pos]<len(digits):
        return
      cur_val[pos]=0
    cur_val.append(0)

  def _get_val(cur_val):
    digit_val=1
    num_val=0
    for x in cur_val:
      num_val+=digits[x]*digit_val
      digit_val*=10
    return num_val

  cur_val=[]
  sum=0
  while(True):
    _next_val(cur_val)
    num_val=_get_val(cur_val)
    if num_val>max_val:
      break
    sum+=num_val
  return sum

def main():
  digits=[4,5,6]
  max_val=666554
  print(digits, max_val)
  print(compute_sum(digits, max_val))

答案 2 :(得分:5)

数学是好的,但并非所有问题都是“可压缩的”,所以知道如何在没有数学的情况下处理它们是值得的。

在这个问题中,求和是微不足道的,难以有效地枚举需要添加的数字,乍一看。

“过滤”路线是一种可能性:逐步生成所有可能的数字,并过滤掉那些不匹配的数字;但是它(通常)效率也很低:

  • 条件可能不容易匹配:在这种情况下,更简单的方法是转换为字符串(在分区和测试上相当繁重),然后是字符串匹配
  • 过滤率不是太高,不能以每个数字30%开头,但它的标度非常差gen-y-s评论:对于4位数字,它是1%,或生成并检查100个数字只得到1个。

因此,我建议采用“世代”方法:只生成符合条件的数字(以及所有数字)。

我会注意到,生成由4,5和6组成的所有数字就像计数(三元组):

  • 从4开始
  • 45变为46(谨防结转)
  • 66变为444(极端结转)

让我们在Python中作为一个生成器:

def generator():
    def convert(array):
        i = 0
        for e in array:
            i *= 10
            i += e
        return i

    def increment(array):
        result = []
        carry = True

        for e in array[::-1]:
            if carry:
                e += 1
                carry = False
            if e > 6:
                e = 4
                carry = True
            result = [e,] + result

        if carry:
            result = [4,] + result

        return result

    array = [4]
    while True:
        num = convert(array)
        if num > 666554: break

        yield num
        array = increment(array)

其结果可以打印sum(generator())

$ time python example.py
409632209
python example.py  0.03s user 0.00s system 82% cpu 0.043 total

here is the same in C++

答案 3 :(得分:2)

“从一个更简单的问题开始。” -Polya

  

将仅由数字4,5,6组成的n位数字相加

正如余浩在上面解释的那样,有3**n个数字,它们的对称平均值是例如。 555555,所以总和为3**n * (10**n-1)*5/9。但如果你没有发现,那么你可以用另一种方式解决问题。

问题有一个递归构造,所以让我们尝试递归解决方案。设g(n)是正好n位数的所有456个数的总和。然后我们有递归关系

g(n) = (4+5+6)*10**(n-1)*3**(n-1) + 3*g(n-1)

要看到这一点,请将总和中每个数字的第一个数字分开(例如,对于n = 3,数百列)。这给了第一个任期。第二项是剩余数字的总和,每个前缀4,5,6的g(n-1)计数。

如果仍然不清楚,写出n = 2的总和并从单位中分开数十:

g(2) = 44+45+46 + 54+55+56 + 64+65+66
     = (40+50+60)*3 + 3*(4+5+6)
     = (4+5+6)*10*3 + 3*g(n-1)

冷却。在这一点上,敏锐的读者可能想检查余浩的g(n)公式是否满足我们的递归关系。

为了解决OP的问题,从4到666666的所有456个数的总和是g(1) + g(2) + g(3) + g(4) + g(5) + g(6)。在Python中,使用动态编程:

def sum456(n):
    """Find the sum of all numbers at most n digits which consist of 4,5,6 only"""
    g = [0] * (n+1)
    for i in range(1,n+1):
        g[i] = 15*10**(i-1)*3**(i-1) + 3*g[i-1]
    print(g) # show the array of partial solutions
    return sum(g)

对于n = 6

>>> sum456(6)
[0, 15, 495, 14985, 449955, 13499865, 404999595]
418964910

编辑:我注意到OP在666554处截断了他的总和,因此它不适合一般模式。这将是最后几个词

>>> sum456(6) - (666555 + 666556 + 666564 + 666565 + 666566 + 666644 + 666645 + 666646 + 666654 + 666655 + 666656 + + 666664 + 666665 + 666666)
409632209

答案 4 :(得分:0)

4到666666的总和是:

rest = 666555+666556+666564+666565+666566+
666644+666645+666646+
666654+666655+666656+
666664+666665+666666
>>> 9332701

total - rest
>>> 409632209

666554和666666之间的少数数字的总和是:

<span on-some-event="displayIndex(index)"></span>

答案 5 :(得分:0)

Java实现问题:- 这将使用模(10 ^ 9 +7)作为答案。

public static long compute_sum(long[] digits, long max_val, long count[]) {
    List<Long> cur_val = new ArrayList<>();
    long sum = 0;
    long mod = ((long)Math.pow(10,9))+7;
    long num_val = 0;
    while (true) {
        _next_val(cur_val, digits);
        num_val = _get_val(cur_val, digits, count);
        sum =(sum%mod + (num_val)%mod)%mod;
        if (num_val == max_val) {
            break;
        }

    }
    return sum;
}

public static void _next_val(List<Long> cur_val, long[] digits) {
    for (int pos = 0; pos < cur_val.size(); pos++) {
        cur_val.set(pos, cur_val.get(pos) + 1);
        if (cur_val.get(pos) < digits.length)
            return;
        cur_val.set(pos, 0L);
    }

    cur_val.add(0L);
}

public static long _get_val(List<Long> cur_val, long[] digits, long count[]) {
    long digit_val = 1;
    long num_val = 0;
    long[] digitAppearanceCount = new long[]{0,0,0};
    for (Long x : cur_val) {
        digitAppearanceCount[x.intValue()] = digitAppearanceCount[x.intValue()]+1;
        if (digitAppearanceCount[x.intValue()]>count[x.intValue()]){
            num_val=0;
            break;
        }
        num_val = num_val+(digits[x.intValue()] * digit_val);
        digit_val *= 10;
    }
    return num_val;
}


public static void main(String[] args) {

    long [] digits=new long[]{4,5,6};
    long count[] = new long[]{1,1,1};
    long max_val= 654;

    System.out.println(compute_sum(digits, max_val, count));
}

@ gen-y-s(https://stackoverflow.com/a/31286947/8398943)给出的答案是错误的(x = y = z = 1包含556.64,44,超过了可用的4s,5s,6s)。输出为12189,但对于x = y = z = 1,输出应为3675。

@Yu Hao(https://stackoverflow.com/a/31285816/8398943)的逻辑与上述错误相同。输出为12189,但对于x = y = z = 1,输出应为3675。