羅区P4213 [テンプレート]ドゥふるいを教える(和)杜が教えるふるいです

P4213 [テンプレート]ドゥがふるいを教える(和)

タグ

  • ドゥは、ふるいを教えます

序文

  • ドゥは〜画面テンプレートを教えます
  • 予備知識は線形スクリーン、メビウス反転、ディリクレ畳み込みである - 、あなたが少しを学ぶ必要がない場合は、再度デュ画面を教えるために学ぶ〜

質問の簡潔な意味

  • リクエスト\(\ MU \)\(\ファイ\)の範囲内のプレフィックスと、\(2 ^ {31} -1 \) 複数の問い合わせ。

考え

  • ドゥは、テンプレート画面を教えます。まず、コアデュ篩は、以下の式に教示されている
    (1)。\ [Gを* S(N)= \ sum_ 1} ^ {N-I =(F * G)(I) - \ sum_ I = {2} ^ NG(I)S [\ FRACのNI] \]
  • 限り決定観測として\(G \)ブロック上式プレフィックスと最後尾。だから、乗法の機能のために、限り、我々は見つけると
  1. プレフィックスと簡単に見つけること
  2. ディリクレ畳み込み機能の本来の機能を簡単に合計

関数gは、それを行うことができます。

  • 見てください\(\ミュー\)機能。簡単に知っている\(\ * MU I = \イプシロン\) そして作る(GはI \ =)\を、その後、最初の\(グラム\)\(私は\)我々が求める、置換を\(\ MUは、\)置き換える置換(Fを\)\を \
    [\ SUM \ limits_ 1} ^ {N-I =(\ G * MU)(I)= \ SUM \ limits_ 1} ^ {N-I =(\ MU *。 I)(I)\]

    \(\ MU * I = \の イプシロン\)は、 一般的に使用される式です。証明:
    • ディリクレ畳み込み\(\ MU * I = \和\ limits_ | MU \ {D N}(D)* I([\ FRACのND])\)
    • そして\(I(X)= 1 \) 上記式に、知ることができる\(\ MU * I = \和\ limits_ {D | N}ミュー\(D)\)
    • そしてメビウス反転が(もメビウス関数特性と呼ばれることもある)を知ることができる(\和の\ limits_ {D \ |ミュー(D)= [N == 1] = \イプシロン\ \ nは}) :、そこには、元の式に代入する
      \ [\ * I MU = \イプシロン\]
  • 知ることは容易である(\ \ * I MU = \イプシロン\) それは元の式であろうように:
    \ [\ SUM \ limits_ 1} ^ {N-I = \イプシロン(I)= [N-> = 1] \。]
  • 単純に素晴らしい祈りました。それは次のようになり、この式に元:
    \ [S(N)= [N-> = 1] - \ sum_ {2} = I ^ナノ秒[\ FRACのNi] \。]
  • 第二の問題は、式を見つけるために今ある(\ \ SUM \ limits_ I = {2} ^ NG(I)[\ FRAC Niは] \ s)は、単純な、それをブロックします。

----------------------------------------------分割線鳩 - ---------------------------------------------

  • 今求めている\(\ファイ\)プレフィックスをして。フロントアヒルとほぼ非常にシンプル。セルフ〜それを導出します
    ----------------------------------------------サブハトライン----------------------------------------------
  • このすべての最初の検索のメモリですが、意志ひどくQAQ T
  • 最適化。ドゥは、ふるいを教えるが、線形複雑度よりも低いが、グループがどのようにアヒルを尋ねました!場合は、問い合わせの複数のセット、線形画面の複雑さが、(線形ふるい杜がふるいを教えるよりも優れた\(O(N \) の前処理、その後、\(O(1)\)ので、クエリが、杜のティーチング画面...)我々は、先に線形ふるいを見て前処理を行うことができふるいのうち、\(\ミューと\ファイ\)プレフィックス、その後デュ画面がはるかに高速に教えることができます!

注意事項

  • 5E6線形事前ふるいふるいおそらくより適切な〜

概要

  • これは一般的なディリクレ畳み込みを記憶して、関数gはすぐにする時間を見つけました!ここでは、一般的なディリクレ畳み込みを要約したものです。
  • \(\ムー* I = \イプシロン\)
  • \(PHI \ * I =のid \)

ACコード

#include<cstdio>
#include<unordered_map>
using namespace std;

const int maxn = 5e6 + 10;

bool no_prime[maxn];
int prime[maxn], mu[maxn], phi[maxn], p_mu[maxn];
long long p_phi[maxn];
int shai(int n)
{
    int cnt = 0;
    mu[1] = phi[1] = 1;

    for (int i = 2; i <= n; i++)
    {
        if (!no_prime[i])
            prime[++cnt] = i, mu[i] = -1, phi[i] = i - 1;

        for (int j = 1; j <= cnt && prime[j] * i <= n; j++)
        {
            no_prime[i * prime[j]] = 1;
            mu[i * prime[j]] = i % prime[j] == 0 ? 0 : -mu[i];
            phi[i * prime[j]] = i % prime[j] == 0 ? phi[i] * prime[j] : phi[i] * (prime[j] - 1);
            if (i % prime[j] == 0) break;
        }
    }

    for (int i = 1; i <= n; i++)
        p_mu[i] = p_mu[i - 1] + mu[i], p_phi[i] = p_phi[i - 1] + phi[i];

    return cnt;
}

unordered_map<int, int> rec_mu;
unordered_map<int, long long> rec_phi;

int pre_mu(int n)
{
    if (n <= maxn - 10) return p_mu[n];
    if (rec_mu[n]) return rec_mu[n];

    int l = 2, r, ans = (n >= 1);
    while (l <= n)
    {
        r = n / (n / l);
        ans -= (r - l + 1) * pre_mu(n / l);
        l = r + 1;
    }
    return rec_mu[n] = ans;
}

long long pre_phi(int n)
{
    if (n <= maxn - 10) return p_phi[n];
    if (rec_phi[n]) return rec_phi[n];

    int l = 2, r;

    long long ans = n % 2 == 0 ? 1ll*n / 2ll * (n + 1) : (n + 1ll) / 2ll * n;
    while (l <= n)
    {
        r = n / (n / l);
        ans -= (r - l + 1) * pre_phi(n / l);
        if (l == 2147483647) break;
        l = r + 1;
    }
    return rec_phi[n] = ans;
}

void solve()
{
    shai(maxn - 10);

    int t;
    scanf("%d", &t);
    while (t--)
    {
        int n;
        scanf("%d", &n);

        printf("%lld %d\n", pre_phi(n), pre_mu(n));
    }
}

int main()
{
    solve();
    return 0;
}

おすすめ

転載: www.cnblogs.com/danzh/p/11302352.html