zoukankan      html  css  js  c++  java
  • BZOJ1101——莫比乌斯函数&&入门

    题目

    链接

    有$50000$次查询,对于给定的整数$a,b$和$d$,有多少正整数对$x$和$y$,满足$x leq a$,$y leq b$,并且$gcd(x, y)=d$。$1 leq k leq a,b leq 50000$.

    分析

        求有多少对$(x,y)$满足$x leq a$,$y leq b$,并且 $gcd(x, y)=d$,等价于求有多少对$(x, y)$满足$x leq frac{a}{d}, y leq frac{b}{d}$并且$x, y$互质.

         设$D(a, b, d)$表示满足$x leq a, y leq b$且$d | gcd(x, y)$的二元组的对数。显然只要$x, y$都是$d$的倍数即可。$1 sim a$之间$d$的倍数有$left lfloor frac{a}{d} ight floor$个。故$D(a, b, d) = left lfloor frac{a}{d} ight floor left lfloor frac{b}{d} ight floor$.

        设$F(a, b)$ 表示满足$x leq a$,$y leq b$ 且 $x, y$互质的二元组的对数。根据容斥原理:

    $$F(a,b)=sum_{i=1}^{min(a,b)} mu(i)*D(a,b,i)$$

        上式的意思是,没有任何限制的二元组总数为 $D(a, b, 1)=a*b$,应该减去$gcd(a, b)$是$2,3,5 cdots$的倍数的二元组数量,这样又重复减掉了$gcd(a, b)$既是$2$的倍数、又是$3$的倍数的二元组数量,应该加回来。依此类推,$D(a, b, i)$的系数恰好就是莫比乌斯函数.

        由整除分块的知识,我们知道:$forall i in [x, min(left lfloor a/ left lfloor a/x ight floor ight floor), left lfloor b/left lfloor b/x ight floor ight floor]$,$D(a,b,i)=left lfloor a/i ight floorleft lfloor b/i ight floor$ 的值都是相等的,预处理出莫比乌斯函数的前缀和,即可直接累加这一段的答案。这样的段只有$O(2sqrt{min(a,b)})$个.

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int maxn = 50000 + 10;
     5 int miu[maxn],vis[maxn], smiu[maxn];
     6 
     7 void getmiu(int n)
     8 {
     9     for(int i=1;i <= n;i++)  miu[i]=1, vis[i];
    10     for(int i=2;i <= n;i++)
    11     {
    12         if(vis[i])  continue;
    13         miu[i] = -1;    //i没有被访问,说明i是素数
    14         for(int j = 2*i; j <= n;j += i)
    15         {
    16             vis[j] = 1;
    17             if(j % (i*i) == 0)  miu[j] = 0;  //含有平方因子
    18             else  miu[j] *= -1;
    19         }
    20     }
    21 
    22     for(int i = 1;i <= n;i++)  smiu[i] = smiu[i-1] + miu[i];
    23 }
    24 
    25 int f(int a, int b)
    26 {
    27     int ans = 0;
    28     for(int l=1, r; l <= min(a, b);l = r+1)
    29     {
    30         r = min(a / (a / l), b / (b / l));
    31         ans += (smiu[r] - smiu[l-1]) * (a/l) * (b/l);   //按段累加
    32         //printf("%d  %d
    ", l, r);
    33     }
    34     printf("%d
    ", ans);
    35 }
    36 
    37 int main()
    38 {
    39     int T;
    40     scanf("%d", &T);
    41     getmiu(maxn);
    42     //for(int i=1; i <= 20;i++)  printf("%d
    ", miu[i]);
    43     while(T--)
    44     {
    45         int a, b, k;
    46         scanf("%d%d%d", &a, &b, &k);
    47         f(a/k, b/k);
    48     }
    49     return 0;
    50 }

        

  • 相关阅读:
    第 01 组 Alpha 事后诸葛亮
    第 01 组 Alpha 冲刺(4/4)
    第 01 组 Alpha 冲刺(3/4)
    第 01 组 Alpha 冲刺(2/4)
    第 01 组 Alpha 冲刺(1/4)
    学习日志-2021.11.08
    论文阅读-2021.11.06
    学习日志-2021.10.25
    学习日志-2021.10.24
    学习日志-2021.10.18
  • 原文地址:https://www.cnblogs.com/lfri/p/11174781.html
Copyright © 2011-2022 走看看