第2章 数字之魅——数字中的技巧2.8

2.8找符合条件的整数

问题描述:给定一个正整数N,求一个最小正整数M(M>1),使得N*M的十进制表示形式里只含有1和0.

最直接了当的方法。当然就是对M无限穷举下去。

书上提供了一个逆向考虑的方法。

其实重点是思想。

我们可以穷举N*M。即由1和0构成的串。

相比穷举M而言。N*M的数量级小得多了多!。

而且我们判断合法的时候只要判断构造出来的串是否整除N.即可。

相似的。曾经遇到过一个这样的问题。

输入数据N,M。其中0<N<M<1e9。打印出[N,M]中的回文素数。

有常识的话。可以知道1e9素数数量有500W。我们并不容易能够先筛出素数表。

即使空间允许。时间也不允许。

而这时。我们可以考虑去构造回文串。回文串的数量比素数的数量小得多。然后我们再去判断构造出来的回文数是否是素数。

对于这个问题。已经包含了“避多就少”的转化思想。

于是我们同样地可以思考这样的一个问题。已知N. 求M

使得N*M为一个回文素数。

这个问题就不加以分析了。

回归正题。

然而我们并不满足于穷举0 1串的复杂度(实际上其复杂度还是相当高的)。

这里利用和式的同余定理:

a mod p = m1 , b mod p = m2  -> (a+b) mod p = (a mod p + b mod p) mod p = (m1+m2) mod p 

针对整除问题的优化。

根据长度对我们构造出来的串进行划分。

1     10,11   100,101,110,111 ...

容易发现一个问题。

长度长的串除了原串 (1 10 100...)以外。都是由原串和长度小的串构成的。

比如 111 是由 100 + 11.

       110 是由 100 + 10.

       101 是由 100 + 1.

由此。我们可以利用动态规划的思想。保留处理出的结果为后续使用。(这里的结果其实就是余数)。

同时你会发现一个问题。

假如N = 3.

1  mod 3 = 1. 10 mod 3 = 1.即1 和 10 对于3 来说是等价的。

那么同理。  101 110 对于3来说也是等价的。

我们是否可以避免101 110这样的运算的呢?

答案当然是可以的。

我们可以只保留余数信息。同时可以在这个余数信息里存最小的串元素。

比如 BigInt[1] = 1.

这样的话。我们就不会重复计算同余数的数了。

套用编程之美上面的伪码。

<代码>

代码上令BigInt[]  为向量数组。方便操作。

同时放入i 是为了防止更新在当前长度新产生的余数集。

就比如:N = 3 的例子

1%3 = 1 有余数集1。

10%3 = 1 。余数集1已经存在。那么更新1+1 = 2 的余数集。

(在这之前都没问题,看下面。)

100%3 = 1 。余数集1已经存在。那么我们对余数集1 2 进行更新操作。 1+1=2 已经存在。 1+2 = 3 更新出3的集

(这是正常的操作)。

假如没有放入i。

就会变成

100%3 = 1。 余数1存在略过。1+1 = 2 存在略过。1+3 = 3 更新出3。之后又 1+3 = 4 更新出4 。 1+4 = 5 更新出 5 。

原文地址:https://www.cnblogs.com/Milkor/p/4506805.html