1. 程式人生 > >[BZOJ4916]神犇和蒟蒻 杜教篩/Min_25篩

[BZOJ4916]神犇和蒟蒻 杜教篩/Min_25篩

答案 var 範圍 i++ sum pre getc max urn

題目大意:

給定\(n\le 10^9\),求:

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

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

解釋

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

直接輸出1

因為對於\(\forall i>1\)\(\mu (i^2)=0\)

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

for 杜教篩:

構造函數\(f(i)=\varphi(i^2)\),則有\(f*\mathrm{id}=id^2\),具體推導:

\(\sum_{d|n}\varphi(d^2)\frac n d=\sum_{d|n}d\varphi(d)\frac n d=n\sum_{d|n}d=n^2\)

杜教板子:(風格不太清真,好久以前寫的)

#include <bits/stdc++.h>
#define maxn 3000010
#define p 1000000007
#define int long long
using namespace std;
 
map<int, long long> ans_phi;
bool vis[maxn];
int prime[maxn], tot;
long long phi[maxn];
long long inv2, inv6;
 
long long qpow(long long a, long long b)
{
    long long res = 1;
    while (b > 0)
    {
        if (b & 1)
            res = res * a % p;
        a = a * a % p;
        b >>= 1;
    }
    return res;
}
 
void prework()
{
    inv2 = qpow(2, p - 2);
    inv6 = qpow(6, p - 2);
    phi[1] = 1;
    for (int i = 2; i <= 3000000; i++)
    {
        if (vis[i] == 0)
        { 
            prime[++tot] = i;
            phi[i] = i - 1;
        }
        for (int j = 1; j <= tot && prime[j] * i <= 3000000; j++)
        {
            vis[i * prime[j]] = 1;
            if (i % prime[j] == 0)
            {
                phi[i * prime[j]] = phi[i] * prime[j] % p;
                break;
            }
            else
                phi[i * prime[j]] = phi[i] * (prime[j] - 1) % p;
        }
        phi[i] = i * phi[i] % p;
        (phi[i] += phi[i - 1]) %= p;
    }
}
 
long long S_phi(int n)
{
    if (n <= 3000000)
        return phi[n];
    if (ans_phi.count(n))
        return ans_phi[n];
    long long ans = 1LL * (2 * n + 1) * (n + 1) % p * n % p * inv6 % p;
    for (int l = 2, r; l <= n; l = r + 1)
    {
        r= n / (n / l);
        ans = ((ans - (r - l + 1) * (l + r) % p * S_phi(n / l) % p * inv2 % p) % p + p) % p;
    }
    return ans_phi[n] = ans;
}
 
void read(int &x)
{
    static char ch;
    x = 0;
    ch = getchar();
    while (!isdigit(ch))
        ch = getchar();
    while (isdigit(ch))
    {
        x = x * 10 + ch - 48;
        ch = getchar();
    }
}
 
signed main()
{
    prework();
//  int T;
//  read(T);
//  for (int n, i = 1; i <= T; i++)
//  {
        int n;
        read(n);
        printf("1\n%lld\n", S_phi(n));
//  }
    return 0;
}

for Min_25篩:

\(f(p)=\varphi(p^2)=p\varphi(p)=p^2-p\)

對於質數我們需要篩一個g2,一個g1,方便判斷質數最好再篩一個g0

快速計算\(f(p^k)\)部分也可以參考Sum的Min_25篩寫法

因為\(\sum_{i=2}^ni^2\)\(n\)為1e9時的答案為333333333833333333500000000,遠超long long的範圍,要開__int128,由於擔心出點什麽鍋,所以我就懶得寫Min_25篩的代碼了。

[BZOJ4916]神犇和蒟蒻 杜教篩/Min_25篩