【问题标题】:Count the number of number x that has digit sum equal the digit sum of x*m计算数字总和等于 x*m 的数字总和的数字 x 的数量
【发布时间】:2015-12-10 13:32:54
【问题描述】:

我试图解决以下问题,但我被卡住了。我认为这是一个动态规划问题。 可以给点意见吗?

问题:

给定一个正数 n (n

例子:

n= 1, m= 2 结果= 2

n= 18,m=1 结果 = 1000000000000000000

提前致谢。

【问题讨论】:

  • 我不明白这个问题。我的姿势似乎不太好。在您的第一个示例中: x=2, S(x)=S(2)=2; S(xm)=S(4)=4,违反了S(x)=S(xm)。在第二种情况下,当 m=1 时,任何 n 位数字都是一个解。
  • 如果 DP 能在这里工作,我会感到非常惊讶。为什么你认为它会在这里工作?首先,我会寻找一些规则/模式。例如,被 9 整除,根据 (m modulo 9) 您可以自动限制可能的值。当然,如果 m=1,10,100,那么答案是显而易见的。 m = k*10 的答案与 m = k 的答案相同。仍然对于 n = 18,我看不出有任何方法可以在宇宙终结之前解决这个问题。
  • @isanco。结果是 2,因为[0, 9] 是可能的答案。
  • @Washington Guedes。谢谢,我现在明白了。
  • sjsu.edu/faculty/watkins/Digitsum0.htm 有一些数字和属性,ii 看起来(尽管值得怀疑)这样的问题的结果可以直接计算。

标签: c++ algorithm c++11 dynamic-programming


【解决方案1】:

首先,我们需要想出一个递归公式:

从最低有效位 (LSD) 到最高有效位 (MSD),如果在计算 MSD 后,我们有 S(x) = S(x*m),我们就有一个有效的解决方案

要验证一个数是否为有效解,我们需要知道三件事:

  • 数字 S(x) 的当前总和是多少
  • 数字 S(x*m) 的当前总和是多少
  • 当前数字是多少。

所以,要回答第一个和最后一个,很容易,我们只需要维护两个参数sumdigit。要计算第二个,我们需要维护两个附加参数,sumOfProductlastRemaining

  • sumOfProduct 是当前的 S(x*m)
  • lastRemaining(m * current digit value + lastRemaining) / 10 的结果

例如,我们有x = 123m = 23

  • 第一个数字 = 3

    sum = 3
    digit  = 0
    sumOfProduct += (lastRemaining + 3*m) % 10 = 9
    lastRemaining = (m*3 + 0)/10 = 6
    
  • 第二个数字 = 2

    sum = 5
    digit = 1
    sumOfProduct += (lastRemaining + 2*m) % 10 = 11
    lastRemaining = (m*2 + lastRemaining)/10 = 5
    
  • 最后一位 = 1

    sum = 6
    digit = 2
    sumOfProduct += (lastRemaining + m) % 10 = 19
    lastRemaining = (m + lastRemaining)/10 = 2
    

    因为这是最后一位数字,sumOfProduct += S(lastRemaining) = 21

因此,x = 123m = 23 不是有效数字。检查x*m = 2829 -> S(x*m) = S(2829) = 21

所以,我们可以有一个状态为(digit, sum, sumOfProdut, lastRemaining) 的递归公式。

因此,我们的动态编程状态是dp[18][18*9 + 1][18*9 + 1][200](因为m lastRemaining 不大于200)。

现在dpstate 超过 300 MB,但如果我们使用迭代方法,它会变得更小,大约使用 30 MB

【讨论】:

    【解决方案2】:

    这个问题可以直接计算。

    根据这些文件:123(感谢 @LouisRicci 找到它们),我们可以声明:

    1. 倍数之和的重复循环从最后一位开始重复,但从基数开始重复(9 表示基数为 10)

    2. S(x) 可以定义为:让a 等于x mod 9,如果a 为零,则取9 作为结果,否则取a你可以在下面的 ES6 sn-p 中播放它:

    IN.oninput= (_=> OUT.value= (IN.value % 9) || 9);
    IN.oninput();
    Input x:<br>
    <input id=IN value=123><br>
    
    S(x):<br>
    <input id=OUT disabled>
    1. 乘法规则:S(x * y) = S(S(x) * S(y))

    2. S(x)S(x*m) 对于x=0 将始终为真,这样就不会产生零结果。


    考虑到以上陈述,我们应该计算S(m)的倍数和的重复周期:

    int m = 88;
    int Sm = S(m); // 7
    
    int true_n_times_in_nine = 0;
    for (int i=1; i<=9; i++) {
        true_n_times_in_nine += i == S(i * Sm);
    }
    

    那么答案:

    result = ((pow(10, n) / 9) * true_n_times_in_nine);
    

    因为大小写为零而加一:

    result++;
    

    这是一个 ES6 解决方案:

    S= x=> (x % 9) || 9;
    TrueIn9= (m, Sm=S(m))=> [1,2,3,4,5,6,7,8,9].filter(i=> i==S(i*Sm)).length;
    F= (n,m)=> ~~(eval('1e'+n)/9) * TrueIn9(m) + 1;
    
    
    N.oninput= 
    M.oninput= 
    f=(_=> OUT.value= F(N.value | 0, M.value | 0));
    f();
    Input n: (number of digits)<br>
    <input id=N value=1><br>
    
    Input m: (multiplicative number)<br>
    <input id=M value=2><br>
    
    F(n,m):<br>
    <input id=OUT disabled><br>

    【讨论】:

      猜你喜欢
      • 2022-07-07
      • 1970-01-01
      • 1970-01-01
      • 2021-12-08
      • 1970-01-01
      • 2012-03-11
      • 2012-10-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多