题解 P4466 【[国家集训队]和与积】

星小雨

2019-01-21 23:37:24

Solution

前置知识:莫比乌斯反演 算是一道相对基础的反演题了吧。。 求有多少组$a,b$,满足$1 \le a<b \le n$且$(a+b)|ab$ 由于$n \le 10^9 $,反演看起来势在必行 首先是一个很显然的结论:若$(a,b)=1$,则$(a+b) \nmid ab$ 为什么呢?因为此时$(a+b,a)=(a+b,b)=1$ 所以$(a,b) \ne 1$ 所以我们可以设$d=(a,b),a=di,b=dj$,则$(i+j)|ijd$ 因为$(i,j)=1$,由上述推论可得$(i+j) \nmid ij$ 所以这道题也就是求$(i+j)|d$,$(i,j)=1$且$id,jd \le n$的$(i,j,d)$的数目。 推推式子吧: $ ans =\sum _{i=1}^n \sum _{j=1}^{i-1} \lfloor \frac {\lfloor \frac{n}{i} \rfloor }{i+j} \rfloor [(i,j) = 1] $ $=\sum_{i=1}^{n}\sum_{j=1}^{i-1} \lfloor \frac {n}{i(i+j) } \rfloor [(i,j)=1]$ $i$最多取到$\sqrt n$,不然后面的$\lfloor \frac {n}{i(i+j) } \rfloor$就等于0了,所以 $ ans=\sum_{i=1}^{\sqrt n}\sum_{j=1}^{i-1} \lfloor \frac {n}{i(i+j) } \rfloor [(i,j)=1]$ 套一个莫比乌斯函数的基本操作$[x=1] = \sum_{d|x} \mu (d)$,得: $ ans= \sum_{i=1}^{\sqrt n}\sum_{j=1}^{i-1} \lfloor \frac {n}{i(i+j) } \rfloor \sum_{k|(i,j)} \mu(k) $ 设$i=xk,j=yk$,则: $ ans = \sum_{k=1}^{\sqrt n} \mu(k) \sum_{x=1}^{\lfloor \frac{\sqrt{n}}{k} \rfloor} \sum_{y=1}^{x-1} \lfloor \frac {n}{xk(xk+yk) } \rfloor $ $ =\sum_{k=1}^{\sqrt n} \mu(k) \sum_{x=1}^{\lfloor \frac{\sqrt{n}}{k} \rfloor} \sum_{y=1}^{x-1} \lfloor \frac {\lfloor \frac{n}{xk^2} \rfloor }{x+y} \rfloor$ 枚举了$k,x$之后,$\frac{n}{xk^2}$是固定值,而它除以$x+y$显然可以使用数论分块。 代码如下: ```cpp #include<cmath> #include<cstdio> #include<algorithm> typedef long long ll; const int N=1e5+5; bool b[N]; int p[N],u[N]; ll calc(int x,int y){ ll a=0;int z=x<<1; if(!y) return 0; for(int i=x+1;i<z;i=x+1){ if(!(y/i)) return a; x=std::min(y/(y/i),z-1); a+=(x-i+1)*(y/i); } return a; } int main(){ int t=0,n,m,x;ll a=0; scanf("%d",&n); m=sqrt(n); u[1]=1; for(int i=2;i<=m;++i){ if(!b[i]) p[++t]=i,u[i]=-1; for(int j=1;j<=t && (x=i*p[j])<=m;++j){ b[x]=1,u[x]=-u[i]; if(!(i%p[j])){u[x]=0;break;} } } for(int i=1;i<=m;++i){ if(!u[i]) continue; for(int j=1;j*i<=m;++j) a+=u[i]*calc(j,n/(i*i*j)); } printf("%lld\n",a); return 0; } ``` 时间复杂度我感觉是最多 $ O( n^{\frac{3}{4}} \text{ln} \sqrt n) $的吧。。 不过洛咕上有大神证出了是 $O( \sqrt n \text log n)$的?问号问号。。