闭区间内模d为r的数有几个?

——有些时候,一些看起来简单的问题,可没那么简单。
本文禁止一切形式的转载,仅允许极少数句子的引用

  • 在这篇文章里面,你会看到编程语言的一些关于整数除法的细节,以及一种解决区间上一些问题的方案。

  • 问题的精确描述

    在区间[a, b]上,有多少个数字,对d整数除法,得到的结果是r?
    用代码描述一下:
    int i;
    for (i = a; i <= b; i++) {
        if (i % d == r)
            s++;
    }
    printf("%d", s);
    
    好吧,用循环做很简单,但是如果\(b-a\)很大呢?
    这个时候就得要推导一下了。
  • 问题解决方案:

    • 分而治之
      先解决一个更加简单的问题,在[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))
      
      得到的是
      0
      
      (但是python里,-1//2是可以的,大概是自带向下取整吧)
      所以,对于浮点数取整数,编程语言里面很有可能是直接截断小数部分,所以-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是负数,就不一定正确了。
  • 实战