BZOJ 3994 [SDOI2015]约数个数和 (莫比乌斯反演)

题目大意:略

洛谷传送门

首先要知道这样一个公式不知道这个公式这道题还怎么做...

 

$d(ij)=\sum\limits_{x=1}^{i} \sum\limits_{y=1}^{j}[gcd(x,y)==1]$

具体证明可以参考这位神犇的博客

大意是说,令$k=i \cdot j$,把$k,i,j$都分解成质因子幂次乘积的形式

那么对于其中一个质因子$p$,$k,i,j$里,$p$的幂次分别为$c,a,b$

那么因为$p^{c}=p^{a} \cdot p^{b},c=a+b$

对于$k$的所有约数,$p$能取的幂次是$0,1,2...c$,一共$c+1=a+b+1$种取值

而在上述式子中,保证$x,y$互质,则$x,y$中$p$的指数,$x$取$0$,$y$取$[1,b]$,或者$x$取$[1,a]$,$y$取$0$,或者$x,y$都取$0$,一共$a+b+1$种取值,和上述论证吻合

而质因子之间互不影响,所以推广到多个质因子上,这个结论依然是正确的

 

进入正题,我们有了这个公式,下面的推导就十分经典套路

$\sum\limits_{i=1}^{n} \sum\limits_{j=1}^{m} \sum\limits_{x|i} \sum\limits_{y|j} [gcd(x,y)==1]$

$\sum\limits_{i=1}^{n} \sum\limits_{j=1}^{m} \sum\limits_{x|i} \sum\limits_{y|j} \sum\limits_{d|gcd(x,y)} \mu(d)$

$\sum\limits_{d=1}^{n} \mu(d) \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}\sum\limits_{x|i}\sum\limits_{y|j}[d|gcd(x,y)]$

$\sum\limits_{d=1}^{n} \mu(d) \sum\limits_{x=1}^{n}\sum\limits_{y=1}^{m} \left \lfloor \frac{n}{x} \right \rfloor \left \lfloor \frac{m}{y} \right \rfloor [d|gcd(x,y)]$

$\sum\limits_{d=1}^{n} \mu(d) \sum\limits_{x=1}^{n} \left \lfloor \frac{n}{dx} \right \rfloor \sum\limits_{y=1}^{m} \left \lfloor \frac{m}{dy} \right \rfloor$ 

令$g(n)=\sum\limits_{x=1}^{n} \left \lfloor \frac{n}{x} \right \rfloor$

则$\sum\limits_{d=1}^{n} \mu(d) g(\left \lfloor \frac{n}{d} \right \rfloor) g(\left \lfloor \frac{m}{d} \right \rfloor )$

$g(n)$可以利用整除分块的思想在$O(n\sqrt n)$的时间内预处理出来

对于每个询问也用整除分块求解即可,总时间$O(T\sqrt n+n\sqrt n)$

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

 

posted @ 2019-01-05 14:13  guapisolo  阅读(163)  评论(0编辑  收藏  举报