Du teach sieve learning summary

Du teach sieve learning summary

Foreword

Du teach sieve has been heard very nb, but learning about it has been pigeon = = but recently encountered too many math problems spicy, so had to fill up the pit.

Recommended blog:
Portal 1
Portal 2
Portal 3

In addition Du teach sieve may take some pre-knowledge, prior written an article on Mobius function, just the way it Tieshanglai: Portal

text

Arithmetical functions : we usually encounter some special functions such as \ (\ varphi, \ mu \ ) that belong to the arithmetical functions.

Multiplicative function :
Definition: If a known function of the number theoretic function, and \ (F (. 1). 1 = \) , and satisfies for any two coprime \ (P, Q \) , there are: \ (F ( P \ CDOT Q) = F (P) \ CDOT F (Q) \) , then called \ (F \) is a multiplicative function. Specially, if for any two numbers \ (the p-, q \) , there \ (f (the p-\ cdot q) = f (the p-) \ cdot f (q) \) , then it is called such functions as complete multiplicative function.

Common multiplicative function:

  • \ (\ MU (the n-) \) - Mobius function, which is very common, it needs to have some understanding of nature;
  • \ (\ varphi (n-) \) - Euler function, is defined as \ (. 1 \) ~ \ (\ n-) with (n-\) \ the number of prime numbers;
  • \ (d (n) \) number divisor number, represents a number of from about -.

  • (Complete multiplicative function):
  • \ (\ varepsilon (n-) \) - membership function, when \ (n = 1 \) when its value is 1, the remaining time value of 0;
  • \ (The I (n-) \) - the identity function, regardless of the \ (n-\) what value of the constant value which is equal to 1;
  • \ (ID (n-) \) - function units, \ (ID (n-) = n-\) ;

These seemingly completely multiplicative function is relatively simple, in fact, has a lot of use. They are completely multiplicative nature is well-proven.

Dirichlet convolution:
Definition: two functions \ (f (n), g (n) \) is referred to as a Dirichlet convolution \ ((F * G) (n-) \) , expression is equivalent to \ (\ sum_ {D |} n-F (D) G (\ {n-FRAC} {D}) \) . In front of the parentheses indicate the convolution of the object, the latter in parentheses indicate the range of the convolution.
Nature :
Dirichlet convolution operation has some very useful properties:

  • Exchange Rate: \ (F * F * G = G \) ;
  • Associativity: \ ((F * G) = F * H * (G * H) \) ;
  • Distributive law: \ (F * (G + H) + = F * F * G H \) .

There is also a more important nature:
if \ (f, g \) are multiplicative function, then \ (f * g \) is also multiplicative function.
Du teach sieve, to judge by the convolution product of the function, it is a very common technique.
In addition to the above mentioned our membership function \ (\ varepsilon \) , there are \ (\ varepsilon F = F * \) , i.e., the unit acts like element 1 in the multiplication function.

application:

  • For Mobius function \ (\ MU \) , there are \ (\ * the I MU = \ varepsilon \) ;
  • For Euler function \ (\ varphi \) , there \ (\ varphi the I * the above mentioned id = \) .

More than two expressions is one of the most commonly used functions of these two properties. They can also be used to prove something by:
For example, for a form of Mobius inversion, it is known \ (F = f * the I \) , which we will roll on both sides simultaneously \ (\ MU \) , so and so it is a type \ (MU = * F * F. \ varepsilon = F \) , i.e. \ (F * = F. \ MU \) .
It is not feeling a lot easier to prove some of it?
There For \ (\ varphi the I = ID * \) , while on both sides of the roll \ (\ MU \) , then there is \ (\ varphi = id * \ mu = \ sum_ {d | n} d \ mu (\ {} {D n-FRAC}) \) . This equation is also useful.
In short, master \ (\ mu, \ varphi \ ) the nature and Dirichlet convolution is very good.

Du teach sieve

In front are some pre-knowledge, then we come to the question - Du teach sieve friends.
Du is used primarily in the sieve teachings pressure linear time \ (O (n ^ {\ frac {2} {3}}) \) is obtained in the multiplicative function and prefix. I am not feeling very powerful? Well, in fact, teach Du screen is not so magical, look down to know ~

Now for multiplicative function \ (F \) , requires \ (\ sum_ = {I}. 1 ^ NF (I) \) , which will be referred to as \ (S (n-) \) .
Configuration \ (F * G = H \) , then there is:
\ [\ the aligned the begin {} \ sum_ {I}. 1 ^ = NH (I) = & \ sum_ {I}. 1 = G ^ * NF = & \\ \ sum_ {i = 1} ^ n \ sum_ {d | i} f (\ frac {i} {d}) g (d) \\ = & \ sum_dg (d) \ sum_ {d | i} f (\ frac {i} {d})
\\ = & \ sum_dg (d) S (\ lfloor \ frac {n} {d} \ rfloor) \\ \ end {aligned} \] now the first singled, then there is:
\ [\ sum_ {I}. 1 ^ = NH (I) G = (. 1) \ CDOT S (n-) + \ sum_ {D} ^ 2 = ng (D) S (\ lfloor \ {n-FRAC } {d} \ rfloor) \
] expression is equivalent to:
\ [G (. 1) \ CDOT S (n-) = \ sum_. 1} ^ {n-I = (F * G) (I) - \ sum_ {D = 2} ^ ng (d) S (\ lfloor \ frac {n} {d} \ rfloor) \]

If we can find a multiplicative function \ (G \) , so \ (\ sum_ {i = 1 } ^ n (f * g) (i) \) prefix of this part and capable of quickly seeking, while the rear divisible directly block, it can play a role in accelerating.

A few common examples to illustrate it:

  • \(\sum_{i=1}^n\mu(i)\)

We know: \ (\ * MU the I = \ varepsilon \) , and \ (\ varepsilon \) This function is simple enough! It is summed quickly, so we make \ (G = \ varepsilon \) , then can be summed into the equation:
\ [S (n-) = l- \ sum_ {D} = 2 ^ nS (\ lfloor \ frac {n} {d}
\ rfloor) \] to the rear portion, the block processing may be divisible.

  • \(\sum_{i=1}^n\varphi(i)\)

Or the use of \ (\ varphi \) character, we know when its volume \ (I \) , it is possible to become a relatively simple function: \ (the above mentioned id \) . This sum is to support the fast, then we direct access to \ (g = I \) can be.

  • \ (\ sum_ {i = 1 ^ ni} \ varphi (i) \) .

This looks like not so good deal, suppose we have a \ (G \) , we will be represented in the form of convolution: \ (\ sum_ {d | the n-} (d \ varphi (d)) G (\ FRAC n-D} {} {) \) .
Observe this formula, when the \ (g = id \) , the multiple to a \ (D \) can be eliminated, and the remaining a \ (n-\) can be mentioned outside.
So naturally think take \ (g = id \) it, then \ ((F * G) (I) = I \ sum_ {D |} n-\ varphi (D) = I \) .
Is not feeling quite wonderful, the equation becomes very simple.

  • \ (\ sum_ {i = 1} ^ ni ^ 2 \ varphi (i) \) .

The same with the above idea, first write out the convolution form, there are: \ (\ sum_ {D | D ^ n-2} \ varphi (D) G (\ {n-FRAC} {D}) \) .
Similarly, conceivable to make \ (G = ID \) , there are: \ (\ sum_ {I = NF * G. 1} ^ = \ sum_ = {I}. 1 ^ Ni ^ 2 \) , it is actually the same as above routine ~

Anyway looking for \ (g \) This step requires a certain observation and patience, it is not a a test on the line.

If a specific implementation may be implemented recursively, \ (GetSum (n-) \) can be obtained \ (S (n-) \) , then the processing may be recursive.
It proved then you can use the main theorem card directly DU taught sieve, then the complexity is \ (O (n ^ {\ frac {3} {4}}) \) , we can first pre-out \ (n ^ {\ frac {2} {3 }} \) prefix and, as is the complexity of the \ (O (n ^ {\ frac {2} {3}}) \) a.
Can add a memory of the operation, it may be faster, especially for a plurality of sets of data is.
Attached below a title template code:
Luo Gu P4213

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e6 + 5;
int mu[N], p[N];
ll phi[N];
bool chk[N];
unordered_map <int, ll> mp1, mp2;
void init() {
    mu[1] = phi[1] = 1;
    int cnt = 0, k = N - 1;
    for(int i = 2; i <= k; i++) {
        if(!chk[i]) p[++cnt] = i, mu[i] = -1, phi[i] = i - 1;
        for(int j = 1; j <= cnt && i * p[j] <= k; j++) {
            chk[i * p[j]] = 1;
            if(i % p[j] == 0) {mu[i * p[j]] = 0; phi[i * p[j]] = phi[i] * p[j]; break;}
            mu[i * p[j]] = -mu[i]; phi[i * p[j]] = phi[i] * (p[j] - 1);
        }
    }
    for(int i = 1; i < N; i++) mu[i] += mu[i - 1], phi[i] += phi[i - 1];
}
ll djs_mu(int n) {
    if(n <= 5000000) return mu[n];
    if(mp1[n]) return mp1[n];
    ll ans = 1;
    for(int i = 2, j; i <= n; i = j + 1) {
        j = n / (n / i);
        ans -= (j - i + 1) * djs_mu(n / i);
    }
    return mp1[n] = ans;
}
ll djs_phi(int n) {
    if(n <= 5000000) return phi[n];
    if(mp2[n]) return mp2[n];
    ll ans = 1ll * (n + 1) * n / 2;
    for(int i = 2, j; i <= n; i = j + 1) {
        j = n / (n / i);
        ans -= (j - i + 1) * djs_phi(n / i);
    }
    return mp2[n] = ans;
}
int n, T;
int main() {
    init();
    cin >> T;
    while(T--) {
        cin >> n;
        ll ans1 = djs_mu(n);
        ll ans2 = djs_phi(n);
        cout << ans2 << ' ' << ans1 << '\n';
    }
    return 0;
}

Guess you like

Origin www.cnblogs.com/heyuhhh/p/11409516.html