整除问题题解

本题主要考察容斥原理和二维前缀和的应用,是一道较为简单的题目。

20 分的做法

由于 ,我们使用二重循环暴力枚举并去重检查即可,时间复杂度

60 分的做法

由于 ,我们可以使用容斥的办法寻找满足要求的数对个数。注意到 ,我们分两步进行容斥。

中整除 的数字数目,容易得到


  • 因为任何数乘以 2021 都能整除 2021,所以这一步我们可以直接得到 。而在这些数对中, 都能整除 2021 的被计数了两次,我们要减掉。所以,满足这个条件的总数为

  • 由于上面已经计数了单个数为 2021 的情况,这一步我们计数仅能被这其中单个因子整除的数,很容易能得到能被 43 但是不能被 47 整除的数的个数为 ,同理可得只能被 47 整除但是不能被 43 整除的数个数为 。根据乘法原理,直接对 b 和 d 分别计算一下然后乘起来即可,即

将上述两种容斥结果加起来就是答案了。可以看出,上面的数学计算都是常数且为常数个,所以总复杂度

100 分的做法

考虑 60 分的做法,如果我们将 看作一个矩形的左下角,看作一个矩形的右上角的话,我们实际上求出来了在矩形 范围内的点 的个数,其中 。所以,本题被转化为了求矩形 中这样点的个数。我们使用经典的二维前缀和容斥来解决这个问题。

前缀和容斥

观察上图,我们需要求的点都在 范围内,而 根据 60 分的做法我们都可以求出来。这里,我们使用整个矩形的面积减掉 的面积,容易得到 ,发现我们多减掉了一个 ,我们将其加回来即可,此时我们就得到了 的面积。

这就是经典的二维前缀和容斥,由于 60 分的做法只需要 的时间做数学计算,这里也是四个简单的数学计算,所以我们在 的时间内就能解决这个问题。

当然,直接对 进行数论容斥也可以解决这个问题,本质和二维前缀和容斥相同,此处不再赘述。

C++ 参考代码如下:

class Solution {
  using ll = long long;

  ll get_43(ll n) {
    ll ans = n / 43;
    ans = ans - ans / 47;
    return ans;
  }

  ll get_47(ll n) {
    ll ans = n / 47;
    ans = ans - ans / 43;
    return ans;
  }

  ll get_2021(ll n) { return n / 2021; }

  ll get(ll n, ll m) {
    ll ans = 0;
    // 43*47
    ans = ans + get_43(n) * get_47(m);
    ans = ans + get_47(n) * get_43(m);

    // 1*2021
    ans = ans + n * get_2021(m);
    ans = ans + m * get_2021(n);
    ans = ans - get_2021(n) * get_2021(m);

    return ans;
  }

public:
  /**
   * 寻找所有能整除 2021 的数对个数
   * @param A long长整型
   * @param B long长整型
   * @param C long长整型
   * @param D long长整型
   * @return long长整型
   */
  long long findPairs(long long A, long long B, long long C, long long D) {
    ll ans = get(B, D);
    ans = ans - get(A - 1, D);
    ans = ans - get(B, C - 1);
    ans = ans + get(A - 1, C - 1);

    return ans;
  }
};
全部评论

相关推荐

爱看电影的杨桃allin春招:我感觉你在炫耀
点赞 评论 收藏
分享
AFBUFYGRFHJLP:直接去美帝试试看全奖phd吧
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务