Theorem. Let be arithmetic function such that
. Then,
.
Proof.




The Dirichlet Convolution of two function


Denote








The mobius inversion formula and the basic property of mobius functions give


Okay. So what? How can we use this formula to
We can, change our "sum" or our answer using mobius inversion and mobius functions to calculate them fast.
I will give 3 examples which changes the desired sum by using number theory (like mobius function) to calculate them fast.
Example Problems
Problem 1. http://www.spoj.com/problems/LCMSUM/

Let
![$res[x]$](https://latex.artofproblemsolving.com/d/5/2/d522f4398687416341c3b9fec8469181aea630fd.png)

Precalculate


![$res[i \cdot d]$](https://latex.artofproblemsolving.com/6/a/f/6af5b929eae74a719bdb88180608be3c016158d9.png)

![$res[x]+1$](https://latex.artofproblemsolving.com/4/7/e/47e7ac9de4a5e4167e7db01e189234b4a29e26c6.png)
This gives our solution in

#include <stdio.h> #include <iostream> using namespace std; typedef long long int ll; ll res[1000010]; ll phi[1000010]; void preprocess(void) { for(int i=1 ; i<=1000000 ; i++) { phi[i]=i; } for(int i=2 ; i<=1000000 ; i++) { if(phi[i]==i) { for(int j=1; i*j<=n; j++) { phi[i*j]-=phi[i*j]/i; } } } for(int i=1 ; i<=1000000 ; i++) { for(int j=1; i*j<=1000000 ; j++) { res[i*j]+=i*phi[i]; } } } int main(void) { preprocess(); int tc; cin>>tc; while (tc--) { ll n; scanf("%lld",&n); ll ans=res[n]+1; ans=(ans*n)/2; printf("%lld\n",ans); } return 0; }
2. https://www.codechef.com/LTIME13/problems/COPRIME3
Here's the key sum transformation.
We want

Using

Start with


Now let's decide how many








Therefore, our result is
![$\sum_{k=1}^{MAX} \mu (k) \cdot \binom{\text{divcnt}[k]}{3}$](https://latex.artofproblemsolving.com/f/d/5/fd5cb3cdb3e8b2c49e4d393502b84c993495d68c.png)
![$\text{divcnt}[k]$](https://latex.artofproblemsolving.com/9/c/7/9c779dfdfd2c2b7062e89b989276c812a773299b.png)


We can precalculate binomial numbers,

![$\text{divcnt}[k]$](https://latex.artofproblemsolving.com/9/c/7/9c779dfdfd2c2b7062e89b989276c812a773299b.png)



#include <stdio.h> #include <algorithm> #include <vector> #include <string.h> #include <string> #include <stack> #include <queue> #include <iostream> #include <assert.h> #include <math.h> using namespace std; typedef long long int ll; ll primechk[111111]; ll mu[111111]; ll divcnt[111111]; ll cnt[111111]; ll com[333][333]; ll ans, mod=1e7+3; int n; void input(void) { int i, j, x; cin>>n; for(i=1 ; i<=n ; i++) { scanf("%d",&x); cnt[x]++; } } void divpproc(void) { int i, j, x; for(i=1 ; i<=110000 ; i++) { for(j=1 ; i*j<=110000 ; j++) { divcnt[i]+=cnt[i*j]; } } } void compproc(void) { com[0][0]=1; int i, j; for(i=1 ; i<=320 ; i++) { com[i][0]=1; com[i][i]=1; } for(i=2 ; i<=320 ; i++) { for(j=1 ; j<=i-1 ; j++) { com[i][j]=(com[i-1][j-1]+com[i-1][j]); } } } void preprocess(void) { int i, j; for(i=1 ; i<=111100 ; i++) { mu[i]=1; primechk[i]=1; } primechk[1]=0; for(i=2 ; i<=111100 ; i++) { if(primechk[i]==1) { mu[i]=-mu[i]; for(j=2 ; i*j<=111100 ; j++) { primechk[i*j]=0; if(j%i==0) { mu[i*j]=0; } else { mu[i*j]=-mu[i*j]; } } } } } void calc(void) { int i, j; for(i=1 ; i<=105000 ; i++) { ans=ans+mu[i]*com[divcnt[i]][3]; } } int main(void) { preprocess(); input(); divpproc(); compproc(); calc(); cout<<ans; }
3. https://www.codechef.com/COOK29/problems/EXGCD
Here's a sketch. Calculating denominator + calculating inverse of it is just modular inverse calculation.
The main problem is calculating the sum of all gcds. Using

The sum is pretty much

Now change



But this is way easier to calculate! For the


![$\prod_{i=0}^{k-1} \text{number of multiple of } d \text{ in the interval } [A_i,B_i]$](https://latex.artofproblemsolving.com/1/3/0/1300a196f2d7bbfa1487cd3a14b4030c37188bcd.png)
In the more harder problems, the result of mobius inversion gets more complex, and in some problems we also have to keep track of some prefix sums and use the fact that


Comments
Post a Comment