我试图解决以下问题但我被困住了。我认为这是一个动态编程问题。 你能提出一些想法吗?
问题:
给定正数n(n <= 18)和正数m(m <= 100)。 呼叫S(x)是x的数字之和。 例如S(123)= 6 计算具有n位且S(x)= S(x * m)
的整数x的数量示例:
n = 1,m = 2结果= 2
n = 18,m = 1结果= 1000000000000000000
提前致谢。
答案 0 :(得分:6)
首先,我们需要提出一个递归公式:
从最低有效数字(LSD)到最高有效数字(MSD),我们有一个有效的解决方案,如果在我们计算MSD之后,我们有S(x) = S(x*m)
要验证数字是否是有效的解决方案,我们需要了解三件事:
因此,要回答第一个和最后一个,这很简单,我们只需要维护两个参数sum
和digit
。要计算第二个参数,我们需要维护另外两个参数sumOfProduct
和lastRemaining
。
sumOfProduct
是当前的S(x * m)lastRemaining
是(m * current digit value + lastRemaining) / 10
例如,我们有x = 123
和m = 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 = 123
和m = 23
不是有效数字。检查x*m = 2829 -> S(x*m) = S(2829) = 21
。
因此,我们可以使用状态为(digit, sum, sumOfProdut, lastRemaining)
的递归公式。
因此,我们的动态编程状态为dp[18][18*9 + 1][18*9 + 1][200]
(因为m <= 100,因此lastRemaining
不大于200)。
现在dp
状态超过300 MB,但如果我们使用迭代方法,它会变小,使用大约30 MB
答案 1 :(得分:0)
此问题可以直接计算。
从这些文档:1,2和3 (感谢@LouisRicci找到它们),我们可以声明:< / p>
倍数的总和的重复周期开始在最后一位数字处重复,但是从基数开始重复(基数为10的基数为10)
S(x)
可以定义为:让a
等于x mod 9
,如果a
为零,则取9
作为结果,否则取{ {1}}。 您可以在下面的ES6代码段中播放:
a
&#13;
IN.oninput= (_=> OUT.value= (IN.value % 9) || 9);
IN.oninput();
&#13;
乘法规则:Input x:<br>
<input id=IN value=123><br>
S(x):<br>
<input id=OUT disabled>
。
S(x * y) = S(S(x) * S(y))
和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);
这是ES6解决方案:
result++;
&#13;
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();
&#13;