• [HAOI2011]Problem b


    Description

    对于给出的 (n) 个询问,每次求有多少个数对 ((x,y)),满足 (a le x le b)(c le y le d),且 (gcd(x,y) = k)(gcd(x,y)) 函数为 (x)(y) 的最大公约数。

    其中 (1 le n,k le 5 imes 10^4)(1 le a le b le 5 imes 10^4)(1 le c le d le 5 imes 10^4)

    Solution

    首先肯定是自然而然地想到分成四块容斥,即

    [egin{split} sum limits_{i=a}^{b} sum limits_{j=c}^{d} left[ gcd(i,j) = k ight] &= sum limits_{i=1}^{b} sum limits_{j=1}^{d} left[ gcd(i,j) =k ight] \ &- sum limits_{i=1}^{a} sum limits_{j=1}^{d} left[ gcd(i,j) =k ight]\ &- sum limits_{i=1}^{b} sum limits_{j=1}^{c} left[ gcd(i,j) =k ight]\ &+ sum limits_{i=1}^{a} sum limits_{j=1}^{c} left[ gcd(i,j) =k ight] end{split} ]

    这样,每一部分都是 (sum limits_{i=1}^{m} sum limits_{j=1}^{m} left[ gcd(i,j) = k ight]) 的形式。

    接下来考虑如何将式子进行变换:

    [sum limits_{i=1}^{m} sum limits_{j=1}^{m} left[ gcd(i,j) = k ight] = sum limits_{i=1}^{lfloor frac{n}{k} floor} sum limits_{j=1}^{lfloor frac{m}{k} floor} left[ gcd(i,j) = 1 ight] ]

    看到右边的 (left[ gcd(i,j) = 1 ight]) 是不是感觉很熟悉?根据在莫比乌斯反演学习笔记中提到的反演结论

    [left[ gcd(i,j) = 1 ight] iff sum limits_{d mid gcd(i,j)} mu(d) ]

    可以继续化简:

    [sum limits_{i=1}^{lfloor frac{n}{k} floor} sum limits_{j=1}^{lfloor frac{m}{k} floor} sum limits_{d mid gcd(i,j)} mu(d) ]

    考虑变换求和顺序:

    [sum limits_{d=1}^{min(n,m)} mu(d) sum limits_{i=1}^{lfloor frac{n}{k} floor} left[ d mid i ight] sum limits_{j=1}^{lfloor frac{m}{k} floor} left[ d mid j ight] ]

    易知在 (left[ 1, n ight]) 中约数包含 (d) 的数有 (lfloor frac{n}{d} floor) 个,于是式子可以化简为:

    [sum limits_{d=1}^{min(n,m)} mu(d) lfloor frac{lfloor frac{n}{k} floor}{d} floor lfloor frac{lfloor frac{m}{k} floor}{d} floor ]

    再由莫比乌斯反演学习笔记中提到的引理1,可得:

    [sum limits_{d=1}^{min(n,m)} mu(d) lfloor frac{n}{kd} floor lfloor frac{m}{kd} floor ]

    所以最终,就得到了

    [sum limits_{i=a}^{b} sum limits_{j=c}^{d} left[ gcd(i,j) = k ight] = sum limits_{d=1}^{min(n,m)} mu(d) lfloor frac{n}{kd} floor lfloor frac{m}{kd} floor ]

    这个式子就可以利用数论分块进行求解了。

    Code

    Talk is cheap. Show me the code.

    #include <bits/stdc++.h>
    using namespace std;
    
    int ty() {
      int x = 0, f = 1; char ch = getchar();
      while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
      while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
      return x * f;
    }
    
    const int _ = 5e4 + 10;
    int tot, vis[_], p[_], mu[_], sum[_];
    
    void getMu(int lim = 5e4) {
      mu[1] = 1;
      for (int i = 2; i <= lim; ++i) {
        if (!vis[i]) p[++tot] = i, mu[i] = -1;
        for (int j = 1; j <= tot && p[j] * i <= lim; ++j) {
          vis[i * p[j]] = 1;
          if (i % p[j] == 0) {
            mu[i * p[j]] = 0;
            break;
          }
          mu[i * p[j]] = -mu[i];
        }
      }
      for (int i = 1; i <= lim; ++i) sum[i] = sum[i - 1] + mu[i];
    }
    
    int calc(int n, int m, int k) {
      n /= k, m /= k;
      int ret = 0;
      for (int l = 1, r; l <= min(n, m); l = r + 1) {
        r = min(n / (n / l), m / (m / l));
        ret += (sum[r] - sum[l - 1]) * (n / l) * (m / l);
      }
      return ret;
    }
    
    int main() {
      getMu();
      int T = ty(), a, b, c, d, k;
      while (T--) {
        a = ty(), b = ty(), c = ty(), d = ty(), k = ty();
        printf("%d
    ", calc(b, d, k) - calc(a - 1, d, k) - calc(b, c - 1, k) +
                           calc(a - 1, c - 1, k));
      }
      return 0;
    }
    
  • 相关阅读:
    hdu-1162 Eddy's picture---浮点数的MST
    hdu-3371 Connect the Cities---kruskal
    hdu-1879 继续畅通工程---确定部分边的MST
    hdu-1875 畅通工程再续---MST
    hdu1863 畅通工程---MST&连通
    hdu-1233 还是畅通工程---MST模板
    hdu-1232 畅通工程---并查集
    BZOJ3940: [Usaco2015 Feb]Censoring
    BZOJ2434: [Noi2011]阿狸的打字机
    BZOJ2938: [Poi2000]病毒
  • 原文地址:https://www.cnblogs.com/newbielyx/p/13126415.html
Copyright © 2020-2023  润新知