BZOJ 2820 luogu 2257 yy的gcd (莫比乌斯反演)

题目大意:求$gcd(i,j)==k,i\in[1,n],j\in[1,m] ,k\in prime,n,m<=10^{7}$的有序数对个数,不超过10^{4}次询问

莫比乌斯反演入门题

为方便表述,由于n和m等价,以下内容均默认n<=m

题目让我们求:$\sum_{k=1}^{n}\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)==k]$

容易变形为:$\sum_{k=1}^{n}\sum_{i=1}^{\left \lfloor \frac{n}{k} \right \rfloor}\sum_{j=1}^{\left \lfloor \frac{m}{k} \right \rfloor}[gcd(i,j)==1]$

很显然$gcd(i,j)==1$这个东西不太好处理,因为它是最大公约数,直接统计gcd的数量很困难

所以,根据莫比乌斯反演的常规套路

把$gcd(i,j)==1$变形为$\sum _{d|gcd(i,j)}\mu(d)$

可得$\sum_{k=1}^{n}\sum_{i=1}^{\left \lfloor \frac{n}{k} \right \rfloor}\sum_{j=1}^{\left \lfloor \frac{m}{k} \right \rfloor}\sum _{d|gcd(i,j)}\mu(d)$

此时,统计$d$的数量就很容易了,即$\left \lfloor \frac{n}{k} \right \rfloor\cdot \left \lfloor \frac{m}{k} \right \rfloor$,数学含义是"[1,n]中能整除d的数的数量*[1,m]中能整除d的数的数量"

继续变形$\sum_{k=1}^{n}\sum_{d=1}^{\left \lfloor \frac{n}{k} \right \rfloor}\left \lfloor \frac{n}{kd} \right \rfloor \cdot \left \lfloor \frac{m}{kd} \right \rfloor\cdot \mu(d)$

我们看kd这个东西很不爽,把它换掉,令Q=kd

$\sum_{Q}^{n}\left \lfloor \frac{n}{Q} \right \rfloor \cdot \left \lfloor \frac{m}{Q} \right \rfloor\cdot \sum_{k|Q,k\in prime}\mu(\frac{Q}{k})$

$\sum_{k|Q,k\in prime}\mu(\frac{Q}{k})$可以用线性筛筛出,将其命名为$g(i)$,再维护一个前缀和

在线性筛内分三种情况讨论,对于数i,我们遍历到了一个质数$p$,$i$中$p$的幂次为$k$

$k=0$,$i$中不含$p$,根据莫比乌斯函数的性质,$g(i\cdot p)=-g(i)+\mu(i)$,即$g/i$的部分全都反过来,再加上$p$带来的贡献

$k=1$,$i$中含一个$p$,那么在$p$加入后,除了$p$的其它质因子的贡献全部为0,仅计算$p$的贡献,即$g(i\cdot p)=g(i)$

$k>=2$,$i$中含两个$p$,加入$p$后,所有质因子的贡献均为0

而$\sum_{Q}^{n}\left \lfloor \frac{n}{Q} \right \rfloor \cdot \left \lfloor \frac{m}{Q} \right \rfloor$可以使用整除分块(套路的味道)在$O(\sqrt n)$的时间内算出来,再用前缀和统计即可

代码

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define N 10010000
 5 #define maxn 10000000
 6 #define ll long long 
 7 using namespace std;
 8 
 9 int T,n,m,cnt;
10 int mu[N],pr[N],use[N],qm[N];
11 int pm[N];
12 
13 void Pre()
14 {
15     mu[1]=1,qm[1]=1;
16     for(int i=2;i<=maxn;i++)
17     {
18         if(!use[i]) pr[++cnt]=i,mu[i]=-1,qm[i]=1;
19         for(int j=1;j<=cnt&&i*pr[j]<=maxn;j++){
20             use[i*pr[j]]=1;
21             if(i%pr[j]==0){
22                 mu[i*pr[j]]=0;
23                 if((i/pr[j])%pr[j]==0) qm[i*pr[j]]=0;
24                 else qm[i*pr[j]]=mu[i];
25                 break;
26             }else{
27                 mu[i*pr[j]]=-mu[i];
28                 qm[i*pr[j]]=-qm[i]+mu[i];
29             }
30         }
31     }
32     for(int i=1;i<=maxn;i++)
33         pm[i]=pm[i-1]+qm[i];
34 }
35 ll solve(int n,int m)
36 {
37     ll ans=0;//int nd,md;
38     for(int i=2,la,mi=min(n,m);i<=mi;i=la+1)
39     {
40         la=min(n/(n/i),m/(m/i));
41         ans+=1ll*(n/i)*(m/i)*(pm[la]-pm[i-1]);
42     }
43     return ans;
44 }
45 int main()
46 {
47     scanf("%d",&T);
48     Pre();
49     for(int t=1;t<=T;t++)
50     {
51         scanf("%d%d",&n,&m);
52         if(n>m) swap(n,m);
53         printf("%lld\n",solve(n,m));
54     }
55     return 0;
56 }

 

posted @ 2018-11-16 16:03  guapisolo  阅读(173)  评论(0编辑  收藏