The Du Sieve is used to handle a class of prefix sum problems for arithmetic functions. For an arithmetic function \(f\), the Du Sieve can compute \(S(n)=\sum_{i=1}^{n}f(i)\) in sublinear time complexity.
Algorithm Idea
We aim to construct a recurrence relation for \(S(n)\) in terms of \(S\left(\left\lfloor\frac{n}{i}\right\rfloor\right)\).
For any arithmetic function \(g\), the following must hold:
where \(f*g\) is the Dirichlet convolution of the arithmetic functions \(f\) and \(g\).
Brief Proof
\(g(d)f\left(\frac{i}{d}\right)\) contributes to all \(i\leq n\), so we change the order of summation, enumerating \(d\) and \(\frac{i}{d}\) (corresponding to new \(i,j\) respectively):
If we can construct a suitable arithmetic function \(g\) such that:
\(\sum_{i=1}^n(f * g)(i)\) can be computed quickly;
The prefix sum of \(g\) can be computed quickly, to solve \(\sum_{i=2}^ng(i)S\left(\left\lfloor\dfrac{n}{i}\right\rfloor\right)\) using number-theoretic blocking.
Then we can compute \(g(1)S(n)\) in relatively short time.
Note
Regardless of whether the arithmetic function \(f\) is multiplicative, as long as a suitable arithmetic function \(g\) can be constructed, the Du Sieve can be considered for computing the prefix sum of \(f\).
For example, consider \(f(n)=\mathrm{i}\varphi(n)\). Clearly \(f\) is not multiplicative, but we can take \(g(n)=1\), so that:
Computing \(\sum_{k\leq m} (f*g)(k)\) and \(\sum_{k \leq m} g(k)\) both have time complexity \(O(1)\), so the Du Sieve can be considered.
Time Complexity
Let \(R(n)=\left\{\left\lfloor \dfrac{n}{k} \right\rfloor: k=2,3,\dots,n\right\}\). Using the properties of number-theoretic blocking, we know that for any \(m\in R(n)\), \(R(m)\subseteq R(n)\). That is, after using memoization, we only need to compute \(S(k)\) once for all \(k\in R(n)\) to obtain the values for \(R(n)\). The number of such points is \(|R(n)|=O(\sqrt{n})\).
Assume computing \(\sum_{i=1}^n(f * g)(i)\) and \(\sum_{i=1}^n g(i)\) both have time complexity \(O(1)\). Let the time complexity of computing \(S(n)\) be \(T(n)\). Then:
If we can precompute a portion of \(S(k)\), where \(k=1,2,\dots,m\), \(m\geq \lfloor\sqrt n\rfloor\). Let the precomputation time complexity be \(T_0(m)\). Then \(T(n)\) becomes:
If \(T_0(m)=O(m)\) (e.g., linear sieve), by the AM-GM inequality, when \(m=\Theta\left(n^{2/3}\right)\), \(T(n)\) achieves its minimum \(O\left(n^{2/3}\right)\).
An Example of Flawed Proof
Let the complexity of computing \(S(n)\) be \(T(n)\). Then:
Here, \(O\left(\sum_{j=2}^{\lfloor\sqrt{n/i}\rfloor} T\left(\left\lfloor\dfrac{n}{ij}\right\rfloor\right)\right)\) is treated as a higher-order infinitesimal and thus can be discarded. Hence:
The issue lies in the step "treated as a higher-order infinitesimal and thus can be discarded". Substituting \(T\left(\left\lfloor\dfrac{n}{i}\right\rfloor\right)\) into the expression for \(T(n)\) gives:
Consider the part \(\displaystyle\sum_{i=2}^{\lfloor\sqrt{n}\rfloor}\sum_{j=2}^{\lfloor\sqrt{n/i}\rfloor} T\left(\left\lfloor\frac{n}{ij}\right\rfloor\right)\). It is not hard to see:
Since memoization is not introduced, \(T\left(\left\lfloor\sqrt{\dfrac{n}{i}}\right\rfloor\right)\) in the above expression is still \(\Omega\left(\left(\dfrac{n}{i}\right)^{1/4}\right)\). Therefore, the so-called "higher-order infinitesimal" part cannot be discarded.
In fact, the sublinear time complexity of the Du Sieve is guaranteed by memoization. Only after using memoization can we ensure that the multiple summation term does not appear.
Since the problem asks for \(\sum_{i=1}^n \sum_{j=1}^i [\gcd(i,j)=1]\), we exclude the case \(i=1,j=1\) and divide the result by \(2\).
Observe that we only need the prefix sum of the Möbius function to quickly compute the prefix sum of Euler's totient function. Time complexity is \(O\left(n^{\frac 2 3}\right)\).
#include<cstring>#include<iostream>#include<map>usingnamespacestd;constexprintMAXN=2000010;longlongT,n,pri[MAXN],cur,mu[MAXN],sum_mu[MAXN];boolvis[MAXN];map<longlong,longlong>mp_mu;longlongS_mu(longlongx){// Calculate prefix sum of muif(x<MAXN)returnsum_mu[x];if(mp_mu[x])returnmp_mu[x];// If the mu value for this size already exists in the map, return directlylonglongret=(longlong)1;for(longlongi=2,j;i<=x;i=j+1){j=x/(x/i);ret-=S_mu(x/i)*(j-i+1);}returnmp_mu[x]=ret;// Path compression for future calculations}longlongS_phi(longlongx){// Calculate prefix sum of philonglongret=(longlong)0;longlongj;for(longlongi=1;i<=x;i=j+1){j=x/(x/i);ret+=(S_mu(j)-S_mu(i-1))*(x/i)*(x/i);}return(ret-1)/2+1;}intmain(){cin.tie(nullptr)->sync_with_stdio(false);cin>>T;mu[1]=1;for(inti=2;i<MAXN;i++){// Linear sieve preprocessing for mu arrayif(!vis[i]){pri[++cur]=i;mu[i]=-1;}for(intj=1;j<=cur&&i*pri[j]<MAXN;j++){vis[i*pri[j]]=true;if(i%pri[j])mu[i*pri[j]]=-mu[i];else{mu[i*pri[j]]=0;break;}}}for(inti=1;i<MAXN;i++)sum_mu[i]=sum_mu[i-1]+mu[i];// Calculate prefix sum of mu arraywhile(T--){cin>>n;cout<<S_phi(n)<<' '<<S_mu(n)<<'\n';}return0;}
Perform number-theoretic blocking on \(\sum_{d=1}^nF\left(\left\lfloor\dfrac{n}{d}\right\rfloor\right)^2\), and handle the prefix sum of \(d^2\varphi(d)\) using the Du Sieve:
We need to construct a multiplicative function \(g\) such that \(f\times g\) and \(g\) can be summed quickly.
The prefix sum of \(\varphi\) alone can be handled by the Du Sieve with \(\varphi * 1\), but here \(f\) has an extra \(\operatorname{id}^2\), so we convolve with \(\operatorname{id}^2\) to turn it into a constant:
// Do not skimp on array size to save memory, it will cause TLE at 80#include<cmath>#include<iostream>#include<map>usingnamespacestd;constexprintN=5e6,NP=5e6,SZ=N;longlongn,P,inv2,inv6,s[N];intphi[N],p[NP],cnt,pn;boolbp[N];map<longlong,longlong>s_map;longlongksm(longlonga,longlongm){// For calculating modular inverselonglongres=1;while(m){if(m&1)res=res*a%P;a=a*a%P,m>>=1;}returnres;}voidprime_work(intk){// Linear sieve for phi, sbp[0]=bp[1]=true,phi[1]=1;for(inti=2;i<=k;i++){if(!bp[i])p[++cnt]=i,phi[i]=i-1;for(intj=1;j<=cnt&&i*p[j]<=k;j++){bp[i*p[j]]=true;if(i%p[j]==0){phi[i*p[j]]=phi[i]*p[j];break;}elsephi[i*p[j]]=phi[i]*phi[p[j]];}}for(inti=1;i<=k;i++)s[i]=(1ll*i*i%P*phi[i]%P+s[i-1])%P;}longlongs3(longlongk){// Sum of cubesreturnk%=P,(k*(k+1)/2)%P*((k*(k+1)/2)%P)%P;}longlongs2(longlongk){// Sum of squaresreturnk%=P,k*(k+1)%P*(k*2+1)%P*inv6%P;}longlongcalc(longlongk){// Calculate S(k)if(k<=pn)returns[k];if(s_map[k])returns_map[k];// For values exceeding pn, use map for discrete storagelonglongres=s3(k),pre=1,cur;for(longlongi=2,j;i<=k;i=j+1)j=k/(k/i),cur=s2(j),res=(res-calc(k/i)*(cur-pre)%P)%P,pre=cur;returns_map[k]=(res+P)%P;}longlongsolve(){longlongres=0,pre=0,cur;for(longlongi=1,j;i<=n;i=j+1){j=n/(n/i);cur=calc(j);res=(res+(s3(n/i)*(cur-pre))%P)%P;pre=cur;}return(res+P)%P;}intmain(){cin.tie(nullptr)->sync_with_stdio(false);cin>>P>>n;inv2=ksm(2,P-2),inv6=ksm(6,P-2);pn=(longlong)pow(n,0.666667);// n^(2/3)prime_work(pn);cout<<solve();return0;}
References
Ren Zhizhou, 2016, "Several Methods for Summing Multiplicative Functions", 2016 Candidate Papers for the Chinese National Team of the Informatics Olympiad.