闭区间内模d为r的数有几个?
——有些时候,一些看起来简单的问题,可没那么简单。
本文禁止一切形式的转载,仅允许极少数句子的引用
-
在这篇文章里面,你会看到编程语言的一些关于整数除法的细节,以及一种解决区间上一些问题的方案。
-
问题的精确描述
在区间[a, b]上,有多少个数字,对d整数除法,得到的结果是r?
用代码描述一下:
好吧,用循环做很简单,但是如果\(b-a\)很大呢?int i; for (i = a; i <= b; i++) { if (i % d == r) s++; } printf("%d", s);
这个时候就得要推导一下了。 -
问题解决方案:
- 分而治之
先解决一个更加简单的问题,在[0, b]上的解决方案。
为什么是它呢?因为[0, b]上有几个,[0, a - 1]上有几个,一相减,不就是结果了吗?
比如[3, 7]上有3数模2得1,[0, 7]上有4个,[0, 3 - 1]上1个,4-1=3。
好,接下来来解决这个问题。
一个整数可以表达为:\(k * d + r\),基于这个,在[0, b]上有几个模d为r的数,可以转为,有几个k可以做到\(k * d + r \le b\),不能是\(<\),因为b可能刚好就模d为r。
接下来就先变成这个形式:\[k \le \frac{b - r}{d} \]根据不等式:\[n \le \frac{a}{b} < n + 1, n, a, b为正整数 \]可以得出\[n \le \lfloor \frac{a}{b} \rfloor < n + 1 \]得到\[n = \lfloor \frac{a}{b} \rfloor \]接下来, 用它和\[k \le \frac{b - r}{d} \]得到\[k \le \lfloor \frac{b - r}{d} \rfloor \]那么,有几个k能够做到呢?
想想,\(k \in Z^+\),那么\(k \ge 0\)均可,那么可以得到,有\(k - 0 + 1 = k + 1\)个可以,也就是$$ \lfloor \frac{b - r}{d} \rfloor + 1$$
那么,就可以算出来,[a, b]上有几个数能够做到模d为r。 - 整数除法的细节
在c和python里面这么写:
得到的是print(int(-1 / 2))
(但是python里,-1//2是可以的,大概是自带向下取整吧)0
所以,对于浮点数取整数,编程语言里面很有可能是直接截断小数部分,所以-0.5截断后就是0了。这个可以理解,因为这样速度更快。浮点数的实现,就是靠着科学计数法来的。具体有机会再说吧。
所以,不能够直接写成:(b - r) / d + 1
,因为,如果b=0, r = 1, d = 2,结果直接就是1,明显不对, 因为(b - r) / d
不是真正的向下取整,因为它为0。
怎么办?
不妨变一下形式:
$ \lfloor \frac{b - r}{d} \rfloor + 1$
\(= \lfloor \frac{b - r}{d} \rfloor + 1 + 1 - 1\)
\(= \lfloor \frac{b - r + d}{d} \rfloor + 1 - 1\)
\(= \lfloor \frac{b - r + d}{d} \rfloor\)
这下还有个小问题,如果b是负数,就不一定正确了。
- 分而治之
-
实战