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
Precalculate
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
, where We can precalculate binomial numbers,
#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
. Done!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