【问题标题】:How to approach and understand a math related DSA question如何处理和理解与数学相关的 DSA 问题
【发布时间】:2023-01-07 08:08:23
【问题描述】:

我在网上发现了这个问题,我真的不知道这个问题在问什么。如果可能的话,我将非常感谢您在首先理解问题时提供一些帮助,并提供解决方案。谢谢!

判断一个数是否能被 3 整除,需要将其十进制数相加,判断和是否能被 3 整除。 要看一个数是否能被 11 整除,需要将它的十进制表示法分成一对数字(从右端开始),将相应的数字相加并检查总和是否能被 11 整除。

对于任何素数 p(2 和 5 除外)都存在一个整数 r,因此存在类似的整除性测试:要检查一个数是否可​​以被 p 整除,您需要将其十进制表示法拆分为 r 个数字元组(从右端),将这些 r 元组相加并检查它们的和是否可以被 p 整除。

给定一个质数 int p,找到这种可除性测试有效的最小 r 并输出它。

输入由单个整数 p 组成 - 介于 3 和 999983 之间的素数,包括端值,不等于 5。

例子

输入

3个

输出

1个

输入

11

输出

2个

【问题讨论】:

  • 他们要求两件事:1) 找出一种数学方法来表达根据 p 和 r 阐述的关系,然后 2) 编写一个程序来找到所提供 p 的最小 r。

标签: algorithm math data-structures modulo number-theory


【解决方案1】:

这是一个很酷的问题!它使用模运算和一些基本的数论来设计解决方案。

假设我们有p = 11。这里适用什么可分性规则?我们需要一次取多少位才能有整除规则?

好吧,让我们一次尝试一个数字。这意味着,如果我们有 121 并且我们对其数字求和 1 + 2 + 1,那么我们得到 4。但是我们看到,尽管121 可以被11 整除,但4 不能整除,因此该规则不起作用。

如果我们一次取两位数怎么办?使用121我们得到1 + 21 = 22。我们看到22可以被 11 整除,所以这条规则在这里可能有效。事实上,确实如此。对于p = 11,我们有r = 2

这需要一些我无法在文本中传达的直觉(我真的已经尝试过)但是可以证明对于除了25之外的给定素数p,整除规则适用于元组长度为r 的数字当且仅当数字99...9r 9)可被p 整除。事实上,对于p = 3,我们有9 % 3 = 0,而对于p = 11,我们有9 % 11 = 9(这很糟糕)和99 % 11 = 0(这就是我们想要的)。

如果我们想找到这样一个r,我们从r = 1开始。我们检查9是否可以被p整除。如果是,那么我们找到了r。否则,我们会更进一步,检查 99 是否可以被 p 整除。如果是,那么我们返回r = 2。然后,我们检查 999 是否可以被 p 整除,如果是,则返回 r = 3 等等。但是,99...9 数字可能会变得非常大。值得庆幸的是,要检查 p 的整除性,我们只需要存储余数模 p,我们知道它很小(至少小于 999983)。所以 C++ 中的代码看起来像这样:

int r(int p) {
  int result = 1;
  int remainder = 9 % p;
  while (remainder != 0) {
    remainder = (remainder * 10 + 9) % p;
    result++;
  }
  return result;
}

【讨论】:

  • “这需要一点直觉,我无法在文本中表达……”当且仅当 100..0 与 1 mod p 一致时,数字 99..9 才能被 p 整除。由于 Z/pZ 的乘法群是有限的,重复乘以 10 最终会得到 1。这假设 10 不等于 0 mod p,对于不是 10 的因数的素数(即不是 2 或5).
  • 这是一个很好的解释!尽管我认为这绝不是一种“直观”的解释。
  • @Maurycyt 我添加了一个试图从头开始解释的答案。如果您不知道它,我不知道它的可读性如何。但它解释了一个更强的结果——即为什么你只需要考虑划分p-1的权力。
  • 太感谢了!!!!我真的很感激这个有见地的答案。
  • 如果您欣赏它,请点赞它。如果它解决了您的问题,请使用绿色勾号接受它。 ;) 欢迎来到堆栈溢出。
【解决方案2】:

我不知道他们如何期望一个没有背景的随机程序员从中找出答案。

但这里是模运算的简要介绍,应该使这成为可能。

在编程中,n % k 是模运算符。它指的是取n / k的剩余部分。它满足以下两个重要属性:

(n + m) % k = ((n % k) + (m % k)) % k
(n * m) % k = ((n % k) * (m % k)) % k

正因为如此,对于任何k,我们可以认为所有具有相同余数的数字在某种程度上是相同的。结果是所谓的“整数模 k”。它满足您习惯的大部分代数规则。你有结合性、交换性、分配律、0 加法和 1 乘法。

但是,如果 k 是像 10 这样的合数,那么不幸的是 2 * 5 = 10 表示对 102 * 5 = 0 取模。这对除法来说是个问题。

但是如果 k = p 是质数,那么事情就会变得容易得多。如果 (a*m) % p = (b*m) % p 那么 ((a-b) * m) % p = 0 所以 (a-b) * m 可以被 p 整除。因此 (a-b)m 可以被 p 整除。

对于任何非零余数m,让我们看一下序列m % p, m^2 % p, m^3 % p, ...。这个序列无限长,只能取p值。所以我们必须重复a < bm^a % p = m^b %p。所以(1 * m^a) % p = (m^(b-a) * m^a) % p。由于 m 不除 pm^a 也不除,因此 m^(b-a) % p = 1。此外,m^(b-a-1) % p 的行为与m^(-1) = 1/m 一样。 (如果你有足够的数学,你会发现乘法下的非零余数是一个有限群,所有的余数组成一个域。但我们忽略它。)

(我将在所有地方删除 % p。假设它在任何计算中都存在。)

现在让a 成为满足m^a = 1 的最小正数。然后1, m, m^2, ..., m^(a-1)形成一个长度为a的循环。对于1, ..., p-1中的任何n,我们可以形成一个循环(可能相同,可能不同)n, n*m, n*m^2, ..., n*m^(a-1)。可以看出,这些循环分区1, 2, ..., p-1,其中每个数字都在一个循环中,每个循环的长度为a。因此,a 划分p-1。作为旁注,由于ap-1,我们很容易得到Fermat's little theoremm^(p-1)有余数1,因此m^p = m

好的,足够的理论。现在解决你的问题。假设我们有一个基地b = 10^i。他们正在讨论的素数测试是 a_0 + a_1 * b + a_2 * b^2 + a_k * b^k 可以被素数 p 整除当且仅当 a_0 + a_1 + ... + a_k 可以被 p 整除。查看(p-1) + b,这只有在b % p为1时才会发生。如果b % p为1,则在模运算中b的任意幂为1,并且测试有效。

所以我们正在寻找最小的i使得10^i % p1。从我上面显示的,i 总是存在的,并且划分p-1。所以你只需要分解p-1,然后尝试10的每个幂,直到找到最小的i有效。

请注意,您应该在每一步都% p,以防止这些权力变得太大。通过重复平方可以加快计算速度。因此,例如,可以通过依次计算以下各项来计算10^20 % p

10 % p
10^2 % p
10^4 % p
10^5 % p
10^10 % p
10^20 % p

【讨论】:

  • 这令人印象深刻。我应该为我的算法大师班偷这个。我没想到会这样,但这是一个非常酷的问题,结合了埃拉托色尼筛法和费马小定理(而不是寻找模逆)。我想知道是否可以优化找到 p-1 的“有趣”除数。显然,实践中除数的数量受n^(1/3)as seen in this CF blog约束。所以看起来这种方法的复杂性最多(这是一个粗略的估计)O(p^(1/3)log(p))(如果你已经有了因式分解)。
  • @Maurycyt 您实际上可以从best = p-1 开始,对于p-1 的素数分解中的每个素数q,您可以测试best/q 以查看是否可行。每个测试需要O(log(p)) 步,你最多需要O(log(p)) 测试O(log(p)^2)。真正的工作现在是分解。
  • 如果 best 的多个除数 q 有效,我如何知道选择哪一个?这能贪心解决吗?所以让我们假设p = 13,然后我们从best = 12开始。我们都知道12 = 2 * 2 * 3,所以一个可能的q将是2,另一个可能是3。假设best / 2best / 3 都有效。我“下降到”哪一个?如果 best / 2 / 2 实际上是最好的呢?这是一个简单的示例,但可以找到更复杂的示例。我有一种感觉,答案可能是GCD(best / q^k)接管了所有qk“工作”。
  • @Maurycyt 最短的重复将是所有其他重复的 GCD。所以是的,你可以贪婪地解决它。顺便说一句,对于 13,答案是 6。
【解决方案3】:

这是Fermat's little theorem的近乎直接的应用。

首先,你必须重新制定“将十进制符号拆分为元组 [...]”-条件为您可以使用的东西:

要检查一个数是否可​​以被 p 整除,您需要将其十进制表示法拆分为 r 位数字元组(从右端开始),将这些 r 元组相加并检查它们的和是否可以被 p 整除

当你把它从散文翻译成公式时,它本质上说的是你想要

对于任何选择“r-数字元组”b_i 来自{ 0, ..., 10^r - 1 }(只有有限多个b_i 是非零的)。

b_1 = 1和所有其他b_i = 0,很容易看出有必要

更容易看出这也足够了(左侧的所有 10^ri 都简单地转换为因子 1,什么都不做)。

现在,如果 p 既不是 2 也不是 5,那么 10 将不能被 p 整除,因此费马小定理向我们保证

,也就是说,至少存在解决方案r = p - 1。这可能不是最小的 rcomputing the smallest one is hard if you don't have a quantum computer handy

尽管一般来说很难,但对于非常小的p,您可以简单地使用在p 中线性的算法(您只需查看序列

10    mod p 
100   mod p
1000  mod p
10000 mod p
...

并在找到等于1 mod p 的内容后立即停止)。

写成代码,例如,在 Scala 中:

def blockSize(p: Int, n: Int = 10, r: Int = 1): Int =
  if n % p == 1 then r else blockSize(p, n * 10 % p, r + 1)

println(blockSize(3))  // 1
println(blockSize(11)) // 2
println(blockSize(19)) // 18

或者在 Python 中:

def blockSize(p: int, n: int = 10, r: int = 1) -> int:
  return r if n % p == 1 else blockSize(p, n * 10 % p, r + 1)

print(blockSize(3))  # 1
print(blockSize(11)) # 2
print(blockSize(19)) # 18

一堆数字,以防万一其他人想要对替代方法进行合理性检查:

11 -> 2
13 -> 6
17 -> 16
19 -> 18
23 -> 22
29 -> 28
31 -> 15
37 -> 3
41 -> 5
43 -> 21
47 -> 46
53 -> 13
59 -> 58
61 -> 60
67 -> 33
71 -> 35
73 -> 8
79 -> 13
83 -> 41
89 -> 44
97 -> 96
101 -> 4
103 -> 34
107 -> 53
109 -> 108
113 -> 112
127 -> 42
131 -> 130
137 -> 8
139 -> 46
149 -> 148
151 -> 75
157 -> 78
163 -> 81
167 -> 166
173 -> 43
179 -> 178
181 -> 180
191 -> 95
193 -> 192
197 -> 98
199 -> 99

【讨论】:

    【解决方案4】:

    谢谢安德烈·蒂金。

    要记住的简单术语:

    1. 当 x%y =z then (x%y)%y again =z

    2. (X+y)%z == (x%z + y%z)%z 请记住这一点。

      所以你一次把任何数字分解成一些 r 位数字。 IE。将 r=6 时的 3456733 分解为 3 * 10 次方(61) + 446733 * 10 次幂(60).

      你可以将 12536382626373 分解成 12 * 10 次方 (62). + 536382 * 10 功率(61) + 626373 * 10 次方 (6*0)

      注意这里的 r 是 6。

      因此,当我们说我们组合 r 个数字并将它们相加并应用模数时。我们是说我们对上述细分的系数应用模数。

      那么系数和怎么代表整数和呢?

      当“10次方(6空白)”上面分解中的模数变为 1,那么该特定项的模数将等于系数的模数。这意味着 10 次幂 (r空白)无效。您可以使用公式 1 和 2 来检查为什么它没有效果。

      以及以下的 10 次幂 (r任何东西)也将以 1 为模。即如果你能证明 (10 power r)modulo 是 1 那么 (10 power rsomething) 也是 1。

      但重要的是我们应该有 10 次幂 (r) 等于 1。然后每 10 次幂 r* 任何东西都是 1 导致数的模等于 r 数字除以模的总和。

      结论:在(10 r 的次方)中找到 r,使得给定的质数将留下 1 作为提醒。

      这也意味着可被给定质数整除的最小的 9…..9 决定 r。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-06-07
      • 1970-01-01
      • 2012-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多