[SDOI2015]约数个数和

题目大意:
  $q(q\leq50000)$组询问,对于给定的$n,m(n,m\leq50000)$,求$\displaystyle\sum_{i=1}^n\sum_{j=1}^m\tau(ij)$。

思路:
  $\displaystyle\tau(ij)=\sum_{x|i}\sum_{y|j}[\gcd(x,y)==1]$。

$$
\begin{align*}
原式&=\sum_{i=1}^n\sum_{j=1}^m\sum_{x|i}\sum_{y|j}[\gcd(x,y)==1]\\
&=\sum_{i=1}^n\sum_{j=1}^m\sum_{x|i}\sum_{y|j}\sum_{d|\gcd(x,y)}\mu(d)\\
&=\sum_{i=1}^n\sum_{j=1}^m\sum_{d|\gcd(i,j)}\mu(d)\tau(\frac id)\tau(\frac jd)\\
&=\sum_{d=1}^{\min(n,m)}\sum_{i=1}^{\lfloor\frac nd\rfloor}\tau(i)\sum_{j=1}^{\lfloor\frac md\rfloor}\tau(j)
\end{align*}
$$
  其中$\sum\tau(i)$可以线性筛预处理,$d$可以数论分块枚举,单次询问复杂度$O(\sqrt n)$。

 1 #include<cstdio>
 2 #include<cctype>
 3 #include<algorithm>
 4 typedef long long int64;
 5 inline int getint() {
 6     register char ch;
 7     while(!isdigit(ch=getchar()));
 8     register int x=ch^'0';
 9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
10     return x;
11 }
12 const int N=50001,M=5134;
13 bool vis[N];
14 int p[M],mu[N],tau[N],cnt[N],sum_mu[N],sum_tau[N];
15 inline void sieve() {
16     mu[1]=tau[1]=sum_mu[1]=sum_tau[1]=1;
17     for(register int i=2;i<N;i++) {
18         if(!vis[i]) {
19             p[++p[0]]=i;
20             mu[i]=-1;
21             cnt[i]=1;
22             tau[i]=2;
23         }
24         for(register int j=1;j<=p[0]&&i*p[j]<N;j++) {
25             vis[i*p[j]]=true;
26             if(i%p[j]==0) {
27                 mu[i*p[j]]=0;
28                 cnt[i*p[j]]=cnt[i]+1;
29                 tau[i*p[j]]=tau[i]/cnt[i*p[j]]*(cnt[i*p[j]]+1);
30                 break;
31             }
32             mu[i*p[j]]=-mu[i];
33             cnt[i*p[j]]=1;
34             tau[i*p[j]]=tau[i]*2;
35         }
36         sum_mu[i]=sum_mu[i-1]+mu[i];
37         sum_tau[i]=sum_tau[i-1]+tau[i];
38     }
39 }
40 int main() {
41     sieve();
42     for(register int T=getint();T;T--) {
43         const int n=getint(),m=getint(),lim=std::min(n,m);
44         int64 ans=0;
45         for(register int l=1,r;l<=lim;l=r+1) {
46             r=std::min(n/(n/l),m/(m/l));
47             ans+=(int64)(sum_mu[r]-sum_mu[l-1])*sum_tau[n/l]*sum_tau[m/l];
48         }
49         printf("%lld\n",ans);
50     }
51     return 0;
52 }

 

posted @ 2018-02-27 09:02  skylee03  阅读(127)  评论(0编辑  收藏  举报