羅区4213:[テンプレート]杜のティーチふるいです

羅区4213:[テンプレート]杜のティーチふるいです

質問の意味:

  • 与えられた\(N- \のLeq。9 ^ 10 \)
  • 要件:
    • \(ANS1 = \ sum_ {I = 1} ^ N \ PHI(I)\)
    • \(ANS2 = \ sum_ {I = 1} ^ N \ MU(I)\)

アイデア:

  • 杜のティーチふるいです。
  • 自然のディリクレ畳み込み:
    • \(\ *チェスIN = \イプシロン\)、\ (IDで\ PHI * = \)、\ (\ *アラームID = \ PHI \)
  • コア式ふるいデュティーチ:
    • \(G(1)Sは、(N)= \ sum_(I))^ N(* G F {I 1 =} - \ sum_ {I = 2} ^ ngの(I)S(\ FRAC {n}は{I })\)
オイラー機能:
  • \(\ PHI私は\ IDを= *) \(= \ PHI、G = I、F、F * G = ID \)
  • 彼らが知っている\(IDは\)単位関数である:\(上記ID上記\(N)= N-)

  • \(F * G \)接頭辞となる(\ {N-FRAC *(N + 1)} {2} \)\
  • 数論とブロックの後半を解きます。

メビウス関数:
  • \(U * = I \イプシロン\) \(F = \彼の、I = G、G * = F \イプシロン\)
  • \(G \)\(F * G \)プレフィックスと、あまりにも簡単に見つけること。
  • \(G \)は、プレフィックスに等しい(N \)\ \、(F * G \)プレフィックスに等しい\(1 \)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e6;
bool vis[maxn+10];
int primes[maxn+10], cnt;
ll phi[maxn+10], mu[maxn+10];

void init(int n)
{
    phi[1] = 1;
    mu[1] = 1;
    for(int i = 2; i <= n; i++)
    {
        if(!vis[i])
        {
            primes[++cnt] = i;
            phi[i] = i-1;
            mu[i] = -1;
        }
        for(int j = 1; primes[j] <= n/i; j++)
        {
            vis[primes[j]*i] = 1;
            if(i % primes[j] == 0)
            {
                phi[primes[j]*i] = phi[i] * primes[j];
                break;
            }
            else
            {
                phi[primes[j]*i] = phi[i]*(primes[j]-1);
                mu[i*primes[j]] = -mu[i];
            }
        }
    }
    for(int i = 1; i <= n; i++)
    {
        mu[i] += mu[i-1];
        phi[i] += phi[i-1];
    }
}

unordered_map<int, ll> Smu, Sphi;

ll getSphi(int n)
{
    //提前筛好的
    if(n <= maxn) return phi[n];
    //记忆化
    if(Sphi[n]) return Sphi[n];
    //phi * I = id 的前缀和
    ll res = 1ll*n*(n+1)/2;
    for(int l = 2, r; l <= n; l = r+1)
    {
        r = n/(n/l);
        res -= (r-l+1)*getSphi(n/l);
    }
    return Sphi[n] = res;
}

ll getSmu(int n)
{
    if(n <= maxn) return mu[n];
    if(Smu[n]) return Smu[n];
    //原函数的前缀和是1
    //f = mu, g = I
    ll res = 1;
    for(int l = 2, r; l <= n; l = r+1)
    {
        r = n/(n/l);
        res -= (r-l+1)*getSmu(n/l);
    }
    return Smu[n] = res;
}

int main()
{
    init(maxn);
    int T; scanf("%d", &T);
    while(T--)
    {
        int n; scanf("%d", &n);
        printf("%lld %lld\n", getSphi(n), getSmu(n));
    }
    return 0;
}

おすすめ

転載: www.cnblogs.com/zxytxdy/p/12216196.html