数论函数学习笔记

数论函数学习笔记

由多个博客学习组合而成

狄利克雷卷积

所谓的狄利克雷卷积,是定义在数论函数 ( Z + → C 的函数 ) (\Z^+\rightarrow C的函数) (Z+C的函数)间的一种二元运算,可这样定义:

( f ∗ g ) ( n ) : = ∑ x y = n f ( x ) g ( y ) (f*g)(n):=\sum_{xy=n}f(x)g(y) (fg)(n):=xy=nf(x)g(y)

也可以写成:

( f ∗ g ) ( n ) : = ∑ d ∣ n f ( d ) g ( n d ) (f*g)(n):=\sum_{d|n}f(d)g(\frac{n}{d}) (fg)(n):=dnf(d)g(dn)

为了方便讨论先定义一些常用的数论函数符号:

  • 单位函数 ε ( n ) : = { 1 ,   w h i l e   n = 1 0 ,   o t h e r w i s e \varepsilon(n):=\begin{cases} 1, \ while\ n = 1\\0,\ otherwise\end{cases} ε(n):={1, while n=10, otherwise

  • 幂函数 I d k ( n ) : = n k Id_k(n):=n^k Idk(n):=nk.当 k = 1 k = 1 k=1时为恒等函数 I d ( n ) Id(n) Id(n),当 k = 0 k = 0 k=0时为常数函数 1 ( n ) 1(n) 1(n)

  • 除数函数 σ k ( n ) : = ∑ d ∣ n d k \sigma_k(n):=\sum_{d|n}d^k σk(n):=dndk,当 k = 1 k=1 k=1是为因数和函数 σ ( n ) \sigma(n) σ(n),当 k = 0 k=0 k=0时为因数个数函数 σ 0 ( n ) \sigma_{0}(n) σ0(n)

  • 欧拉函数 φ ( n ) \varphi(n) φ(n)

值得注意的是,这些函数都是所谓的积性函数,即满足 f ( 1 ) = 1 f(1) = 1 f(1)=1,且若a,b互质,则有 f ( a ) f ( b ) = f ( a b ) f(a)f(b)=f(ab) f(a)f(b)=f(ab).

其中前两者还是完全积性函数,它们不需要满足a,b互质的条件也符合等式

积性函数之间的狄利克雷卷积还有特殊的性质:

f , g f,g f,g为积性函数,那么 f ∗ g f*g fg也是积性函数

首先 ( f ∗ g ) ( 1 ) = f ( 1 ) ∗ g ( 1 ) = 1 (f*g)(1)=f(1)*g(1)=1 (fg)(1)=f(1)g(1)=1,设 a , b a,b a,b互质则有:

( f ∗ g ) ( a ) ⋅ ( f ∗ g ) ( b ) = ∑ d 1 ∣ a f ( d 1 ) g ( a d 1 ) ⋅ ∑ d 2 ∣ b f ( d 2 ) g ( b d 2 ) = ∑ d 1 ∣ a , d 2 ∣ b f ( d 1 ) f ( d 2 ) g ( a d 1 ) g ( b d 2 ) = ∑ d 1 ∣ a , d 2 ∣ b f ( d 1 d 2 ) g ( a b d 1 d 2 ) (f*g)(a)\cdot(f*g)(b)=\sum_{d1|a}f(d1)g(\frac{a}{d1})\cdot\sum_{d2|b}f(d2)g(\frac{b}{d2})\\ =\sum_{d1|a,d2|b}f(d1)f(d2)g(\frac{a}{d1})g(\frac{b}{d2})\\ =\sum_{d1|a,d2|b}f(d1d2)g(\frac{ab}{d1d2}) (fg)(a)(fg)(b)=d1∣af(d1)g(d1a)d2∣bf(d2)g(d2b)=d1∣a,d2∣bf(d1)f(d2)g(d1a)g(d2b)=d1∣a,d2∣bf(d1d2)g(d1d2ab)

因为 a , b a,b a,b互质,所以就有了 ( f ∗ g ) ( a ) ⋅ ( f ∗ g ) ( b ) = ( f ∗ g ) ( a b ) (f*g)(a) \cdot (f*g)(b)=(f*g)(ab) (fg)(a)(fg)(b)=(fg)(ab)该等式成立

再考虑某些数论函数之间的关系:

除数函数与幂函数

首先根据定义我们有 ( f ∗ 1 ) ( n ) = ∑ d ∣ n f ( d ) ∗ 1 ( n d ) (f*1)(n)=\sum_{d|n}f(d)*1(\frac{n}{d}) (f1)(n)=dnf(d)1(dn)

所以可以有 ( I d k ∗ 1 ) ( n ) = ∑ d ∣ n I d k ( d ) 1 ( n d ) = ∑ d ∣ n d k = σ k ( n ) (Id_k*1)(n) = \sum_{d|n}Id_k(d)1(\frac{n}{d})=\sum_{d|n}d^k=\sigma_k(n) (Idk1)(n)=dnIdk(d)1(dn)=dndk=σk(n)

简写成 ( I d k ∗ 1 ) ( x ) = σ k ( x ) (Id_k*1)(x)=\sigma_k(x) (Idk1)(x)=σk(x)

欧拉函数与恒等函数

( φ ∗ 1 ) ( n ) = ∑ d ∣ n φ ( d ) (\varphi*1)(n)=\sum_{d|n}\varphi(d) (φ1)(n)=dnφ(d)

n = p m n=p^m n=pm时,有:

∑ d ∣ n φ ( d ) = φ ( 1 ) + ∑ i = 1 m φ ( p i ) = 1 + ∑ i = 1 m ( p i − p i − 1 ) = p m = n \sum_{d|n}\varphi(d)=\varphi(1)+\sum_{i=1}^m \varphi(p^i)=1+\sum_{i=1}^m(p^i-p^{i-1})=p^m=n dnφ(d)=φ(1)+i=1mφ(pi)=1+i=1m(pipi1)=pm=n

( φ ∗ 1 ) ( p m ) = p m (\varphi * 1)(p^m)=p^m (φ1)(pm)=pm

现在令 n n n为任意正整数,那么 n = ∏ p m n = \prod p^m n=pm 又因为 ( φ ∗ 1 ) ( n ) (\varphi*1)(n) (φ1)(n)为积性函数,所以 ( φ ∗ 1 ) ( n ) = ∏ p m = n (\varphi * 1)(n)=\prod p^m=n (φ1)(n)=pm=n

所以有 ( φ ∗ 1 ) = I d (\varphi*1)=Id (φ1)=Id

下面对于一些卷积的法则进行证明:

交换律:
( f ∗ g ) ( n ) = ∑ x y = n f ( x ) g ( y ) = ∑ x y = n f ( y ) g ( x ) = ( g ∗ f ) ( n ) (f*g)(n)=\sum_{xy=n}f(x)g(y)\\ =\sum_{xy=n}f(y)g(x)\\ =(g*f)(n) (fg)(n)=xy=nf(x)g(y)=xy=nf(y)g(x)=(gf)(n)

结合律:
( f ∗ ( g ∗ h ) ) ( n ) = ∑ x y = n f ( x ) ∗ ( g ∗ h ) ( y ) = ∑ x y = n f ( x ) ∗ ∑ u v = y g ( u ) ∗ h ( v ) = ∑ x u v = n f ( x ) g ( u ) h ( v ) = ∑ y v = n h ( v ) ∗ ∑ x u = y f ( x ) g ( u ) = ( ( f ∗ g ) ∗ h ) ( n ) (f*(g*h))(n)=\sum_{xy=n}f(x)*(g*h)(y)\\ =\sum_{xy=n}f(x)*\sum_{uv=y}g(u)*h(v)\\ =\sum_{xuv=n}f(x)g(u)h(v)\\ =\sum_{yv=n}h(v)*\sum_{xu=y}f(x)g(u)\\ =((f*g)*h)(n) (f(gh))(n)=xy=nf(x)(gh)(y)=xy=nf(x)uv=yg(u)h(v)=xuv=nf(x)g(u)h(v)=yv=nh(v)xu=yf(x)g(u)=((fg)h)(n)

分配律:
( f ∗ ( g + h ) ) ( n ) = ∑ x y = n f ( x ) ∗ ( g + h ) ( y ) = ∑ x y = n f ( x ) g ( y ) + f ( x ) h ( y ) = ∑ x y = n f ( x ) g ( y ) + ∑ x y = n f ( x ) h ( y ) = ( f ∗ g ) ( n ) + ( f ∗ h ) ( n ) (f*(g+h))(n)=\sum_{xy=n}f(x)*(g+h)(y)\\ =\sum_{xy=n}f(x)g(y) + f(x)h(y)\\ =\sum_{xy=n}f(x)g(y) + \sum_{xy=n}f(x)h(y)\\ =(f*g)(n)+(f*h)(n)\\ (f(g+h))(n)=xy=nf(x)(g+h)(y)=xy=nf(x)g(y)+f(x)h(y)=xy=nf(x)g(y)+xy=nf(x)h(y)=(fg)(n)+(fh)(n)

单位元的用法:
( f ∗ ε ) ( n ) = ∑ d ∣ n f ( d ) ε ( n d ) = f ( n ) (f*\varepsilon)(n)=\sum_{d|n}f(d)\varepsilon(\frac{n}{d})=f(n)\\ (fε)(n)=dnf(d)ε(dn)=f(n)

逆元:

f ∗ g = ε f*g=\varepsilon fg=ε时我们把 g g g称为 f f f的狄利克雷逆元并写作 f − 1 f^{-1} f1
( f ∗ f − 1 ) = ε ( f * f ^ {-1})=\varepsilon (ff1)=ε

莫比乌斯反演

我们定义数论函数 1 1 1的狄利克雷逆元为 μ \mu μ
得到 μ ( x ) = { 1   n = 1 ( − 1 ) m   n = p 1 p 2 . . . p m 0   o t h e r w i s e \mu(x)=\begin{cases} 1 \ n = 1\\(-1)^m\ n = p_1p_2...p_m\\0\ otherwise\end{cases} μ(x)= 1 n=1(1)m n=p1p2...pm0 otherwise

所以有 ( f ∗ 1 ) = g (f*1)=g (f1)=g可推出 f = ( g ∗ μ ) f=(g * \mu) f=(gμ)

下面是几道经典题目的推导

P3455 [POI2007]ZAP-Queries
简要题意

∑ x = 1 a ∑ y = 1 b [ g c d ( x , y ) = d ] \sum_{x=1}^{a}\sum_{y=1}^b [gcd(x,y)=d] x=1ay=1b[gcd(x,y)=d]

推导

∑ x = 1 a ∑ y = 1 b [ g c d ( x , y ) = d ] = ∑ x = 1 ⌊ a d ⌋ ∑ y = 1 ⌊ b d ⌋ [ g c d ( x , y ) = 1 ] = ∑ x = 1 ⌊ a d ⌋ ∑ y = 1 ⌊ b d ⌋ ε ( g c d ( x , y ) ) = ∑ x = 1 ⌊ a d ⌋ ∑ y = 1 ⌊ b d ⌋ ∑ k ∣ g c d ( x , y ) μ ( k ) = ∑ k = 1 n μ ( k ) ∑ x = 1 ⌊ a d k ⌋ ∑ y = 1 ⌊ b d k ⌋ 1 = ∑ k = 1 n μ ( k ) ⌊ a d k ⌋ ⌊ b d k ⌋ \sum_{x=1}^{a}\sum_{y=1}^b [gcd(x,y)=d]\\ =\sum_{x=1}^{\lfloor\frac{a}{d}\rfloor}\sum_{y=1}^{\lfloor\frac{b}{d}\rfloor}[gcd(x,y)=1]\\ =\sum_{x=1}^{\lfloor\frac{a}{d}\rfloor}\sum_{y=1}^{\lfloor\frac{b}{d}\rfloor}\varepsilon(gcd(x,y))\\ =\sum_{x=1}^{\lfloor\frac{a}{d}\rfloor}\sum_{y=1}^{\lfloor\frac{b}{d}\rfloor}\sum_{k|gcd(x,y)}\mu(k)\\ =\sum_{k=1}^{n}\mu(k)\sum_{x=1}^{\lfloor\frac{a}{dk}\rfloor}\sum_{y=1}^{\lfloor\frac{b}{dk}\rfloor}1\\ =\sum_{k=1}^{n}\mu(k)\lfloor\frac{a}{dk}\rfloor\lfloor\frac{b}{dk}\rfloor\\ x=1ay=1b[gcd(x,y)=d]=x=1day=1db[gcd(x,y)=1]=x=1day=1dbε(gcd(x,y))=x=1day=1dbkgcd(x,y)μ(k)=k=1nμ(k)x=1dkay=1dkb1=k=1nμ(k)dkadkb

其中 n = m a x ( a , b ) n=max(a,b) n=max(a,b)

推导到最后一步就可以使用整除分块加速

P2522 [HAOI2011]Problem b
简要题意

∑ i = x a ∑ j = y b [ g c d ( i , j ) = d ] \sum_{i=x}^{a}\sum_{j=y}^b [gcd(i,j)=d] i=xaj=yb[gcd(i,j)=d]

推导

这道题需要想到容斥原理。

将这个式子写成
∑ i = 1 a ∑ j = 1 b [ g c d ( i , j ) = d ] − ∑ i = 1 a ∑ j = 1 y − 1 [ g c d ( i , j ) = d ] − ∑ i = 1 x − 1 ∑ j = 1 b [ g c d ( i , j ) = d ] + ∑ i = 1 x − 1 ∑ j = 1 y − 1 [ g c d ( i , j ) = d ] \sum_{i=1}^{a}\sum_{j=1}^b [gcd(i,j)=d]-\sum_{i=1}^{a}\sum_{j=1}^{y-1} [gcd(i,j)=d]-\sum_{i=1}^{x-1}\sum_{j=1}^b [gcd(i,j)=d]+\sum_{i=1}^{x-1}\sum_{j=1}^{y-1} [gcd(i,j)=d] i=1aj=1b[gcd(i,j)=d]i=1aj=1y1[gcd(i,j)=d]i=1x1j=1b[gcd(i,j)=d]+i=1x1j=1y1[gcd(i,j)=d]
就跟上面那道一样了

P2257 YY的GCD
简要题意

∑ x = 1 n ∑ y = 1 m [ g c d ( x , y ) = p ] \sum_{x=1}^{n}\sum_{y=1}^m [gcd(x,y)=p] x=1ny=1m[gcd(x,y)=p]其中 p p p为任意质数

推导

首先这里筛出质数后称作 p r i m e prime prime数量为 t o t tot tot
∑ x = 1 n ∑ y = 1 m [ g c d ( x , y ) = p ] = ∑ i = 1 t o t ∑ x = 1 n ∑ y = 1 m [ g c d ( x , y ) = p r i m e [ i ] ] = ∑ i = 1 t o t ∑ x = 1 ⌊ n p r i m e [ i ] ⌋ ∑ y = 1 ⌊ m p r i m e [ i ] ⌋ [ g c d ( x , y ) = 1 ] = ∑ i = 1 t o t ∑ d = 1 m a x ( n , m ) μ ( d ) ⌊ n p r i m e [ i ] ∗ d ⌋ ⌊ m p r i m e [ i ] ∗ d ⌋ 这里 T = p r i m e [ i ] ∗ d 可以将式子转化为 = ∑ T = 1 m a x ( n , m ) ⌊ n T ⌋ ⌊ m T ⌋ ∑ k ∣ T , k ∈ p r i m e μ ( T k ) \sum_{x=1}^{n}\sum_{y=1}^m [gcd(x,y)=p]\\ =\sum_{i=1}^{tot}\sum_{x=1}^{n}\sum_{y=1}^m [gcd(x,y)=prime[i]]\\ =\sum_{i=1}^{tot}\sum_{x=1}^{\lfloor\frac{n}{prime[i]}\rfloor}\sum_{y=1}^{\lfloor\frac{m}{prime[i]}\rfloor} [gcd(x,y)=1]\\ =\sum_{i=1}^{tot}\sum_{d=1}^{max(n,m)}\mu(d)\lfloor\frac{n}{prime[i]*d}\rfloor\lfloor\frac{m}{prime[i]*d}\rfloor\\ 这里T=prime[i]*d可以将式子转化为\\ =\sum_{T=1}^{max(n,m)}\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum_{k|T,k\in prime}\mu(\frac{T}{k}) x=1ny=1m[gcd(x,y)=p]=i=1totx=1ny=1m[gcd(x,y)=prime[i]]=i=1totx=1prime[i]ny=1prime[i]m[gcd(x,y)=1]=i=1totd=1max(n,m)μ(d)prime[i]dnprime[i]dm这里T=prime[i]d可以将式子转化为=T=1max(n,m)TnTmkT,kprimeμ(kT)
发现后面一个式子 ∑ k ∣ T , k ∈ p r i m e μ ( T k ) \sum_{k|T,k\in prime}\mu(\frac{T}{k}) kT,kprimeμ(kT)是可以预处理出来的,这样就减少了复杂度

P1829 [国家集训队]Crash的数字表格 / JZPTAB
简要题意

∑ i = 1 n ∑ j = 1 m l c m ( i , j ) \sum_{i=1}^{n}\sum_{j=1}^{m}lcm(i,j) i=1nj=1mlcm(i,j)

推导

∑ i = 1 n ∑ j = 1 m l c m ( i , j ) = ∑ i = 1 n ∑ j = 1 m i j g c d ( i , j ) = ∑ d = 1 m a x ( n , m ) ∑ i = 1 n ∑ j = 1 m i j d [ g c d ( i , j ) = d ] = ∑ d = 1 m a x ( n , m ) ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ i j d [ g c d ( i , j ) = 1 ] = ∑ d = 1 m a x ( n , m ) d ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ i j [ g c d ( i , j ) = 1 ] 设 s u m ( n , m ) = ∑ i = 1 n ∑ j = 1 m i j [ g c d ( i , j ) = 1 ] 化简这个式子 ∑ i = 1 n ∑ j = 1 m i j [ g c d ( i , j ) = 1 ] = ∑ d = 1 m a x ( n , m ) μ ( d ) d 2 ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ i j 设 f ( n , m ) = ∑ i = 1 n ∑ j = 1 m i j 化简这个式子有 ∑ i = 1 n ∑ j = 1 m i j = ∑ i = 1 n i ∑ j = 1 m j = ( n + 1 ) n 2 ⋅ ( m + 1 ) m 2 所以 s u m ( n , m ) = ∑ d = 1 m a x ( n , m ) μ ( d ) ⋅ d 2 ⋅ f ( n d , m d ) 原式 = ∑ d = 1 m a x ( n , m ) d ⋅ s u m ( n d , m d ) \sum_{i=1}^{n}\sum_{j=1}^{m}lcm(i,j)\\ =\sum_{i=1}^{n}\sum_{j=1}^{m}\frac{ij}{gcd(i,j)}\\ =\sum_{d=1}^{max(n,m)}\sum_{i=1}^{n}\sum_{j=1}^{m}\frac{ij}{d}[gcd(i,j)=d]\\ =\sum_{d=1}^{max(n,m)}\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}ijd[gcd(i,j)=1]\\ =\sum_{d=1}^{max(n,m)}d\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}ij[gcd(i,j)=1]\\ 设sum(n,m)=\sum_{i=1}^{n}\sum_{j=1}^{m}ij[gcd(i,j)=1]\\ 化简这个式子\\ \sum_{i=1}^{n}\sum_{j=1}^{m}ij[gcd(i,j)=1]\\ =\sum_{d=1}^{max(n,m)}\mu(d)d^2\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}ij\\ 设f(n,m)=\sum_{i=1}^{n}\sum_{j=1}^{m}ij\\ 化简这个式子有\\ \sum_{i=1}^{n}\sum_{j=1}^{m}ij\\ =\sum_{i=1}^{n}i\sum_{j=1}^{m}j\\ =\frac{(n+1)n}{2}\cdot \frac{(m+1)m}{2}\\ 所以sum(n,m)=\sum_{d=1}^{max(n,m)}\mu(d)\cdot d^2\cdot f(\frac{n}{d},\frac{m}{d})\\ 原式=\sum_{d=1}^{max(n,m)}d\cdot sum(\frac{n}{d}, \frac{m}{d}) i=1nj=1mlcm(i,j)=i=1nj=1mgcd(i,j)ij=d=1max(n,m)i=1nj=1mdij[gcd(i,j)=d]=d=1max(n,m)i=1dnj=1dmijd[gcd(i,j)=1]=d=1max(n,m)di=1dnj=1dmij[gcd(i,j)=1]sum(n,m)=i=1nj=1mij[gcd(i,j)=1]化简这个式子i=1nj=1mij[gcd(i,j)=1]=d=1max(n,m)μ(d)d2i=1dnj=1dmijf(n,m)=i=1nj=1mij化简这个式子有i=1nj=1mij=i=1nij=1mj=2(n+1)n2(m+1)m所以sum(n,m)=d=1max(n,m)μ(d)d2f(dn,dm)原式=d=1max(n,m)dsum(dn,dm)

这里的两个式子都可以用整除分块+前缀和的方式加速

代码
#include <bits/stdc++.h>

const int N = 1e7 + 5, mod = 20101009;

inline int add(int a, int b) { return (a += b) >= mod ? a - mod : a; }
inline int sub(int a, int b) { return (a -= b) < 0 ? a + mod : a; }
inline int mul(int a, int b) { return 1LL * a * b % mod; }

std::vector < int > prime;
int v[N], mu[N], sum[N];
void input(int n) {
    mu[1] = 1;
    for(int i = 2; i <= n; ++i) {
        if(!v[i]) prime.push_back(i), v[i] = i, mu[i] = mod - 1;
        for(auto x : prime) {
            if(x > n / i) break;
            v[i * x] = x;
            if(!(i % x)) {
                mu[x * i] = 0;
                break;
            }
            mu[i * x] = sub(mod, mu[i]);
        }
    }
    for(int i = 1; i <= n; ++i) sum[i] = add(sum[i - 1], mul(mu[i], mul(i, i)));
}

inline int sumij(int i, int j) {
    return mul((1LL * (i + 1) * i / 2) % mod, (1LL * (j + 1) * j / 2) % mod);
}

inline int f(int n, int m) {
    int re = 0;
    for(int l = 1, r; l <= m; l = r + 1) {
        r = std::min(n / (n / l), m / (m / l));
        int cnt1 = n / l, cnt2 = m / l;
        re = add(re, mul(sumij(cnt1, cnt2), sub(sum[r], sum[l - 1])));
    }
    return re;
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int n, m;
    std::cin >> n >> m;
    if(n < m) std::swap(n, m);
    input(n);
    int ans = 0;
    for(int d = 1; d <= n; ++d) {
        ans = add(ans, mul(d, f(n / d, m / d)));
    }
    std::cout << ans << '\n';
    return 0;
}

杜教筛

对于任意一个数论函数 g g g,必满足:
∑ i = 1 n ( f ∗ g ) ( i ) = ∑ i = 1 n ∑ d ∣ i g ( d ) f ( i d ) = ∑ i = 1 n g ( i ) S ( ⌊ n i ⌋ ) \sum_{i=1}^{n}(f*g)(i)=\sum_{i=1}^{n}\sum_{d|i}g(d)f(\frac{i}{d})=\sum_{i=1}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor) i=1n(fg)(i)=i=1ndig(d)f(di)=i=1ng(i)S(⌊in⌋)

重要推论:
g ( 1 ) S ( n ) = ∑ i = 1 n g ( i ) S ( ⌊ n i ⌋ ) − ∑ i = 2 n g ( i ) S ( ⌊ n i ⌋ ) = ∑ i = 1 n ( f ∗ g ) ( i ) − ∑ i = 2 n g ( i ) S ( ⌊ n i ⌋ ) g(1)S(n)=\sum_{i=1}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor)-\sum_{i=2}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor)\\ =\sum_{i=1}^{n}(f*g)(i)-\sum_{i=2}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor) g(1)S(n)=i=1ng(i)S(⌊in⌋)i=2ng(i)S(⌊in⌋)=i=1n(fg)(i)i=2ng(i)S(⌊in⌋)

如果可以构造一个数论函数 g g g使得:

  • 可以快速计算 ∑ i = 1 n ( f ∗ g ) ( i ) \sum_{i=1}^{n}(f*g)(i) i=1n(fg)(i)
  • 可以快速计算 g g g的前缀和,这样就能用数论分块求解 ∑ i = 2 n g ( i ) S ( ⌊ n i ⌋ ) \sum_{i=2}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor) i=2ng(i)S(⌊in⌋)
    则我们可以取 m = 2 3 n m=\frac{2}{3}n m=32n的复杂度求得 g ( 1 ) S ( n ) g(1)S(n) g(1)S(n)
P3768 简单的数学题

∑ i = 1 n ∑ j = 1 n i j g c d ( i , j ) = ∑ i = 1 n ∑ j = 1 n i j ∑ k ∣ i , k ∣ j φ ( k ) = ∑ k = 1 n φ ( k ) ∑ k ∣ i ∑ k ∣ i i j = ∑ k = 1 n φ ( k ) × k 2 × ( ∑ i = 1 ⌊ n k ⌋ i ) 2 = ∑ k = 1 n φ ( k ) × k 2 × ∑ i = 1 ⌊ n k ⌋ i 3 \sum_{i=1}^{n}\sum_{j=1}^{n}ijgcd(i,j)\\ =\sum_{i=1}^{n}\sum_{j=1}^{n}ij\sum_{k|i,k|j}\varphi(k)\\ =\sum_{k=1}^{n}\varphi(k)\sum_{k|i}\sum_{k|i}ij\\ =\sum_{k=1}^{n}\varphi(k)\times k^2 \times (\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}i)^2\\ =\sum_{k=1}^{n}\varphi(k)\times k^2 \times \sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}i^3 i=1nj=1nijgcd(i,j)=i=1nj=1nijki,kjφ(k)=k=1nφ(k)kikiij=k=1nφ(k)×k2×(i=1kni)2=k=1nφ(k)×k2×i=1kni3

φ ( k ) k 2 \varphi(k)k^2 φ(k)k2做杜教筛

k k k看成 I d Id Id函数有, f = I d 2 φ f=Id^2\varphi f=Id2φ,卷一个 g = I d 2 g=Id^2 g=Id2可以得到 ( f ∗ g ) ( n ) = n 3 (f*g)(n)=n^3 (fg)(n)=n3

这里有一个结论就是 I d k Id^k Idk卷一个 I d k Id^k Idk可以看成是 ( I d k ∗ I d k ) ( n ) = n k ( n − φ ( n ) ) (Id^k*Id^k)(n)=n^k(n-\varphi(n)) (IdkIdk)(n)=nk(nφ(n))

Powerful Number筛

Powerful Number(以下叫做PN)的定义:设 n = ∏ i = 1 m p i e i n=\prod_{i=1}^{m}p_i^{e_i} n=i=1mpiei只有所有的 e i > 1 e_i\gt 1 ei>1才能是PN

可以证明PN的数量级是 Θ ( n ) \Theta(\sqrt n) Θ(n )的,也就是可以暴力搜索所有小于 n \sqrt n n 的质数处理出PN

Powerful Number筛其实是杜教筛的升级版本,计算的也是 F ( n ) = ∑ i = 1 n f ( i ) F(n)=\sum_{i=1}^n f(i) F(n)=i=1nf(i) f ( i ) f(i) f(i)是积性函数),但是依然不适用于所有场景。

PN筛的步骤:

  • 找到一个积性函数 g ( n ) g(n) g(n) n n n为质数的时候 g ( p ) = f ( p ) g(p)=f(p) g(p)=f(p),并且 G ( n ) = ∑ i = 1 n g ( i ) G(n)=\sum_{i=1}^n g(i) G(n)=i=1ng(i)
  • 找到一个快速计算 G G G也就是 g g g的前缀和的方法
  • f = g ∗ h f = g*h f=gh,此时有 h h h为积性函数且 h ( 1 ) = 1 h(1) = 1 h(1)=1
  • 最后 F ( n ) = ∑ d = 1 , d   i s   P N n h ( d ) G ( ⌊ n d ⌋ ) F(n)=\sum_{d=1,d\ is\ PN}^{n}h(d)G(\lfloor\frac{n}{d}\rfloor) F(n)=d=1,d is PNnh(d)G(⌊dn⌋)

下面是对于这条公式的证明(可跳过):

首先对于 h h h函数有一个特殊性质:

f ( p ) = g ( p ) h ( 1 ) + g ( 1 ) h ( p ) = g ( p ) h ( p ) = 0 f(p)=g(p)h(1)+g(1)h(p)=g(p)\\ h(p)=0 f(p)=g(p)h(1)+g(1)h(p)=g(p)h(p)=0
因为 h h h是一个积性函数,我们知道 h ( n o t   P N ) = 0 h(not\ PN)=0 h(not PN)=0

于是
F ( n ) = ∑ i = 1 n ∑ d ∣ i h ( d ) ∗ g ( ⌊ i d ⌋ ) = ∑ d = 1 n h ( d ) ∑ i = 1 ⌊ n d ⌋ g ( i ) = ∑ d = 1 n h ( d ) G ( ⌊ n d ⌋ ) = ∑ d = 1 , d   i s   P N n h ( d ) G ( ⌊ n d ⌋ ) F(n)=\sum_{i=1}^n \sum_{d|i}h(d)*g(\lfloor\frac{i}{d}\rfloor)\\ =\sum_{d=1}^n h(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}g(i)\\ =\sum_{d=1}^n h(d)G(\lfloor\frac{n}{d}\rfloor)\\ =\sum_{d=1,d\ is\ PN}^{n}h(d)G(\lfloor\frac{n}{d}\rfloor) F(n)=i=1ndih(d)g(⌊di⌋)=d=1nh(d)i=1dng(i)=d=1nh(d)G(⌊dn⌋)=d=1,d is PNnh(d)G(⌊dn⌋)
得证

P5325【模板】Min_25 筛

给定 f ( p k ) = p k ( p k − 1 ) f(p^k)=p^k(p^k-1) f(pk)=pk(pk1),求 ∑ i = 1 n f ( i ) \sum_{i=1}^n f(i) i=1nf(i)
定义 g ( n ) = I d ( n ) φ ( n ) 此时 G ( n ) 可以通过杜教筛快速得出 G ( n ) = ∑ i = 1 n i 2 − ∑ d = 2 n d ∗ G ( ⌊ n d ⌋ ) 那么我们知道 h ( p k ) 可以枚举计算(法 1 ) 另外也有 h ( p k ) 直接推出的公式 f ( p k ) = ∑ i = 0 k g ( p k − i ) h ( p i ) p k ( p k − 1 ) = ∑ i = 0 k p k − i φ ( p i ) h ( p i ) p k ( p k − 1 ) = ∑ i = 0 k p 2 k − 2 i − 1 ( p − 1 ) h ( p i ) h ( p k ) = p k ( p k − 1 ) − ∑ i = 0 k − 1 p 2 k − 2 i − 1 h ( p i ) h ( p k ) − p 2 h ( p k − 1 ) = p k ( p k − 1 ) − p k + 1 ( p k − 1 − 1 ) − p ( p − 1 ) h ( p k − 1 ) h ( p k ) − p h ( p k − 1 ) = p k + 1 − p k h ( p k ) p k − h ( p k − 1 ) p k − 1 = p − 1 有 h ( p ) = 0 推出 h ( p k ) = ( k − 1 ) ( p − 1 ) p k (法二) 时间复杂度相似但是法二比较好写 定义g(n)=Id(n)\varphi(n)\\ 此时G(n)可以通过杜教筛快速得出\\ G(n)=\sum_{i=1}^n i^2-\sum_{d=2}^n d*G(\lfloor\frac{n}{d}\rfloor)\\ 那么我们知道h(p^k)可以枚举计算(法1)\\ 另外也有h(p^k)直接推出的公式\\ f(p^k)=\sum_{i=0}^k g(p^{k-i})h(p^i)\\ p^k(p^k-1)=\sum_{i=0}^k p^{k-i}\varphi(p^i)h(p^i)\\ p^k(p^k-1)=\sum_{i=0}^k p^{2k-2i-1}(p-1)h(p^i)\\ h(p^k)=p^k(p^k-1)-\sum_{i=0}^{k-1} p^{2k-2i-1}h(p^i)\\ h(p^k)-p^2h(p^{k-1})=p^k(p^k-1)-p^{k+1}(p^{k-1}-1)-p(p-1)h(p^{k-1})\\ h(p^k)-ph(p^{k-1})=p^{k+1}-p^k\\ \frac{h(p^k)}{p^k}-\frac{h(p^{k-1})}{p^{k-1}}=p-1\\ 有h(p)=0推出\\ h(p^k)=(k-1)(p-1)p^k(法二)\\ 时间复杂度相似但是法二比较好写\\ 定义g(n)=Id(n)φ(n)此时G(n)可以通过杜教筛快速得出G(n)=i=1ni2d=2ndG(⌊dn⌋)那么我们知道h(pk)可以枚举计算(法1另外也有h(pk)直接推出的公式f(pk)=i=0kg(pki)h(pi)pk(pk1)=i=0kpkiφ(pi)h(pi)pk(pk1)=i=0kp2k2i1(p1)h(pi)h(pk)=pk(pk1)i=0k1p2k2i1h(pi)h(pk)p2h(pk1)=pk(pk1)pk+1(pk11)p(p1)h(pk1)h(pk)ph(pk1)=pk+1pkpkh(pk)pk1h(pk1)=p1h(p)=0推出h(pk)=(k1)(p1)pk(法二)时间复杂度相似但是法二比较好写

void solve() {
    i64 n;
    std::cin >> n;
    int N1 = 10000000, N2 = sqrt(n);
    std::vector < int > prime, phi(N1 + 1), v(N1 + 1);
    std::vector < MInt > g(N1 + 1), s(N1 + 1);
    phi[1] = 1;
    for(int i = 2; i <= N1; ++i) {
        if(!v[i]) prime.emplace_back(i), v[i] = i, phi[i] = i - 1;
        for(auto x : prime) {
            if(x > N1 / i || x > v[i]) break;
            v[i * x] = x;
            phi[i * x] = phi[i] * (i % x == 0 ? x : x - 1);
        }
    }
    for(int i = 1; i <= N1; ++i) g[i] = 1LL * i * phi[i], s[i] = s[i - 1] + g[i];
    MInt inv6 = MInt(6).inverse(), inv2 = 500000004;
    std::unordered_map < i64 , MInt > mp;
    auto G = [&](auto self, i64 n) -> MInt {
        if(n <= N1) return s[n];
        if(mp.count(n)) return mp[n];
        MInt re = MInt(n) * MInt(n + 1) * MInt(2 * n + 1) * inv6;
        for(i64 l = 2, r; l <= n; l = r + 1) {
            r = std::min(n, n / (n / l));
            re -= (MInt(r) * MInt(r + 1) * inv2 - MInt(l - 1) * MInt(l) * inv2) * self(self, n / l);
        }
        return mp[n] = re;
    } ;
    // std::cout << g[2] << ' ' << g[3] << ' ' << g[6] << ' ' << g[9] << '\n';
    MInt ans = 0;
    auto dfs = [&](auto self, int id, i64 now, MInt re) -> void {
        i64 cnt = 1LL * prime[id] * prime[id];
        if(now > n / cnt) {
            // std::cout << now << ' ' << prime[id] << ' ' << n << '\n';
            ans += re * G(G, n / now);
            return ;
        }
        self(self, id + 1, now, re);
        MInt st = cnt * g[prime[id]];
        i64 las = n / now;
        while(cnt <= las) {
            MInt to = (MInt(cnt) * MInt(cnt - 1) - st);
            self(self, id + 1, now * cnt, re * to);
            if(cnt > las / prime[id]) break;
            st *= prime[id] * prime[id];
            st += to * g[prime[id]];
            cnt *= prime[id];
        }
    } ;
    dfs(dfs, 0, 1, 1);
    std::cout << ans << '\n';
}
void solve() {
    i64 n;
    std::cin >> n;
    int N1 = 10000000, N2 = sqrt(n);
    std::vector < int > prime, phi(N1 + 1), v(N1 + 1);
    std::vector < MInt > g(N1 + 1), s(N1 + 1);
    phi[1] = 1;
    for(int i = 2; i <= N1; ++i) {
        if(!v[i]) prime.emplace_back(i), v[i] = i, phi[i] = i - 1;
        for(auto x : prime) {
            if(x > N1 / i || x > v[i]) break;
            v[i * x] = x;
            phi[i * x] = phi[i] * (i % x == 0 ? x : x - 1);
        }
    }
    for(int i = 1; i <= N1; ++i) g[i] = 1LL * i * phi[i], s[i] = s[i - 1] + g[i];
    MInt inv6 = MInt(6).inverse(), inv2 = 500000004;
    std::unordered_map < i64 , MInt > mp;
    auto G = [&](auto self, i64 n) -> MInt {
        if(n <= N1) return s[n];
        if(mp.count(n)) return mp[n];
        MInt re = MInt(n) * MInt(n + 1) * MInt(2 * n + 1) * inv6;
        for(i64 l = 2, r; l <= n; l = r + 1) {
            r = std::min(n, n / (n / l));
            re -= (MInt(r) * MInt(r + 1) * inv2 - MInt(l - 1) * MInt(l) * inv2) * self(self, n / l);
        }
        return mp[n] = re;
    } ;
    // std::cout << g[2] << ' ' << g[3] << ' ' << g[6] << ' ' << g[9] << '\n';
    MInt ans = 0;
    auto dfs = [&](auto self, int id, i64 now, MInt re) -> void {
        i64 cnt = 1LL * prime[id] * prime[id];
        if(now > n / cnt) {
            // std::cout << now << ' ' << prime[id] << ' ' << n << '\n';
            ans += re * G(G, n / now);
            return ;
        }
        self(self, id + 1, now, re);
        MInt i = prime[id] - 1;
        i64 las = n / now;
        while(cnt <= las) {
            self(self, id + 1, now * cnt, re * i * MInt(cnt));
            if(cnt > las / prime[id]) break;
            i += MInt(prime[id] - 1);
            cnt *= prime[id];
        }
    } ;
    dfs(dfs, 0, 1, 1);
    std::cout << ans << '\n';
}

Min_25筛

使用要求

Θ ( n 3 4 l o g   n ) \Theta(\frac{n^{\frac{3}{4}}}{log\ n}) Θ(log nn43)的时间复杂度下解决积性函数的前缀和问题。

要求 f ( p ) f(p) f(p)是一个关于 p p p的项数较少的多项式或可以快速求值, f ( p c ) f(p^c) f(pc)可以快速求值。

定义说明

p p p没有特殊说明时代表全体质数

i s p r i m e ( n ) isprime(n) isprime(n)表示 n n n为质数时为 1 1 1

p k p_k pk表示全体质数中第 k k k小的质数,特别的 p 0 = 1 p_0=1 p0=1

l p f ( n ) : = [ 1 < n ] m i n { p : p ∣ n } + [ 1 = n ] lpf(n):=[1<n]min\{p:p|n\}+[1=n] lpf(n):=[1<n]min{p:pn}+[1=n]表示 n n n的最小质因数。特别的, l p f ( 1 ) = 1 lpf(1)=1 lpf(1)=1

F p r i m e ( n ) : = ∑ 2 ≤ p ≤ n f ( p ) F_{prime}(n):=\sum_{2\le p \le n}f(p) Fprime(n):=2pnf(p)

F k ( n ) : = ∑ i = 2 n [ p k ≤ l p f ( i ) ] f ( i ) F_k(n):=\sum_{i=2}^n [p_k\le lpf(i)]f(i) Fk(n):=i=2n[pklpf(i)]f(i)

使用方法

观察 F k ( n ) F_k(n) Fk(n)的定义,我们要求 ∑ i = 1 n f ( i ) = F 1 ( n ) + f ( 1 ) = F 1 ( n ) + 1 \sum_{i=1}^n f(i)=F_1(n)+f(1)=F_1(n)+1 i=1nf(i)=F1(n)+f(1)=F1(n)+1

考虑如何求出 F k ( n ) F_k(n) Fk(n)
F k ( n ) = ∑ i = 2 n [ p k ≤ l p f ( i ) ] f ( i )                    = ∑ k ≤ i , p i 2 ≤ n ∑ 1 ≤ c , p i c ≤ n f ( p c ) ( [ c > 1 ] + F i + 1 ( ⌊ n p i c ⌋ ) ) + ∑ k ≤ i , p i ≤ n f ( p i ) = ∑ k ≤ i , p i 2 ≤ n ( ∑ 1 ≤ c , p i c ≤ n f ( p c ) ( [ c > 1 ] + F i + 1 ( ⌊ n p i c ⌋ ) ) + F p r i m e ( n ) − F p r i m e ( p k − 1 ) ) = ∑ k ≤ i , p i 2 ≤ n ( ∑ 1 ≤ c , p i c + 1 ≤ n ( f ( p c ) F i + 1 ( ⌊ n p i c ⌋ ) + f ( p i c + 1 ) ) + F p r i m e ( n ) − F p r i m e ( p k − 1 ) ) F_k(n)=\sum_{i=2}^n [p_k\le lpf(i)]f(i)\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \\ =\sum_{k\le i,p_i^2\le n}\sum_{1\le c,p_i^c\le n}f(p^c)([c>1]+F_{i+1}(\lfloor\frac{n}{p_i^c}\rfloor))+\sum_{k\le i, p_i\le n}f(p_i)\\ =\sum_{k\le i,p_i^2\le n}(\sum_{1\le c,p_i^c\le n}f(p^c)([c>1]+F_{i+1}(\lfloor\frac{n}{p_i^c}\rfloor))+F_{prime}(n)-F_{prime}(p_{k-1}))\\ =\sum_{k\le i,p_i^2\le n}(\sum_{1\le c,p_i^{c+1}\le n}(f(p^c)F_{i+1}(\lfloor\frac{n}{p_i^c}\rfloor)+f(p_i^{c+1}))+F_{prime}(n)-F_{prime}(p_{k-1}))\\ Fk(n)=i=2n[pklpf(i)]f(i)                  =ki,pi2n1c,picnf(pc)([c>1]+Fi+1(⌊picn⌋))+ki,pinf(pi)=ki,pi2n(1c,picnf(pc)([c>1]+Fi+1(⌊picn⌋))+Fprime(n)Fprime(pk1))=ki,pi2n(1c,pic+1n(f(pc)Fi+1(⌊picn⌋)+f(pic+1))+Fprime(n)Fprime(pk1))

最后一步推导的说明

对于满足 p i c ≤ n < p i c + 1 p_i^c\le n< p_i^{c+1} picn<pic+1 c c c,有 ⌊ n p i c ⌋ < p i < p i + 1 \lfloor\frac{n}{p_i^c}\rfloor <p_i<p_{i+1} picn<pi<pi+1

F i + 1 ( ⌊ n p i c ⌋ ) = 0 F_{i+1}(\lfloor\frac{n}{p_i^c}\rfloor)=0 Fi+1(⌊picn⌋)=0

F k ( n ) = 0 ( p k > n ) F_k(n)=0(p_k>n) Fk(n)=0(pk>n)

假设现在已经求出了所有的 F p r i m e ( n ) F_{prime}(n) Fprime(n),那么有两种方式可以求出所有的 F k ( n ) F_k(n) Fk(n)

  • 直接按照递推式计算
  • 从大到小枚举 p p p转移,仅当 p 2 < n p^2<n p2<n时转移增加值不为零,故按照递推式后缀和优化即可。
计算 F p r i m e ( n ) F_{prime}(n) Fprime(n)

一般情况下 f ( p ) f(p) f(p)是一个关于 p p p的低次多项式,可以表示成 f ( p ) = ∑ a i p c i f(p)=\sum a_ip^{c_i} f(p)=aipci

那么对于每个 p c i p^{c_i} pci,其对 F p r i m e ( n ) F_{prime}(n) Fprime(n)的贡献可以表示为 a i ∑ 2 ≤ p ≤ n p c i a_i\sum_{2\le p\le n}p^{c_i} ai2pnpci

分开考虑每个 p c i p^{c_i} pci的贡献,问题就转变为了:给定 n , s , g ( p ) = p s n,s,g(p)=p^s n,s,g(p)=ps,对所有的 m = ⌊ n i ⌋ m=\lfloor\frac{n}{i}\rfloor m=in,求 ∑ p ≤ m g ( p ) \sum_{p\le m}g(p) pmg(p)

设:
G x ( n ) = ∑ 2 ≤ i ≤ n [ i s p r i m e ( i )   o r   p x < l p f ( i ) ] g ( i ) G_x(n)=\sum_{2\le i \le n}[isprime(i)\ or\ p_x<lpf(i)]g(i)\\ Gx(n)=2in[isprime(i) or px<lpf(i)]g(i)
即埃氏筛第 k k k轮晒完后剩下的数的 g g g值之和。

对于一个合数 x x x,必然有 l p f ( x ) ≤ x lpf(x)\le\sqrt{x} lpf(x)x ,则 F p r i m e = G n F_{prime}=G_{\sqrt{n}} Fprime=Gn 故只需筛到 G n G_{\sqrt{n}} Gn 即可

考虑 G G G的边界值, G 0 ( n ) = ∑ i = 2 n g ( i ) G_0(n)=\sum_{i=2}^n g(i) G0(n)=i=2ng(i)

对于转移,考虑埃氏筛的过程,分开讨论每部分的贡献,有:

  • 对于 n < p k 2 n<p_k^2 n<pk2的部分, G G G值不变,即 G x ( n ) = G x − 1 ( n ) G_x(n)=G_{x-1}(n) Gx(n)=Gx1(n)
  • 对于 p k 2 ≤ n p_k^2\le n pk2n部分,被筛掉的数必有质因子 p k p_k pk − g ( p k ) G k − 1 ( ⌊ n p k ⌋ ) -g(p_k)G_{k-1}(\lfloor\frac{n}{p_k}\rfloor) g(pk)Gk1(⌊pkn⌋)
  • 对于第二个部分,会有一些 l p f ( i ) < p k lpf(i)<p_k lpf(i)<pk i i i被减去,加回来的贡献是 g ( p k ) G k − 1 ( p k − 1 ) g(p_k)G_{k-1}(p_{k-1}) g(pk)Gk1(pk1)

则可以得到 G k ( n ) = G k − 1 ( n ) − [ p k 2 ≤ n ] g ( p k ) ( G k − 1 ( ⌊ n p k ⌋ ) − G k − 1 ( p k − 1 ) ) G_k(n)=G_{k-1}(n)-[p_k^2\le n]g(p_k)(G_{k-1}(\lfloor\frac{n}{p_k}\rfloor)-G_{k-1}(p_{k-1})) Gk(n)=Gk1(n)[pk2n]g(pk)(Gk1(⌊pkn⌋)Gk1(pk1))

总结

对于 F k ( n ) F_k(n) Fk(n)的计算,利用第一种方式写一个函数,这个实现难度较低,已经适用于大部分题目。

对于 F p r i m e 的计算 F_{prime}的计算 Fprime的计算,直接按递推式实现即可。

对于 p k 2 ≤ n p_k^2\le n pk2n可以用线性筛预处理出 s k : = F p r i m e ( p k ) s_k:=F_{prime}(p_k) sk:=Fprime(pk)来代替 F k F_k Fk递推式中的 F p r i m e ( p k − 1 ) F_{prime}(p_{k-1}) Fprime(pk1)

相应的 G k − 1 ( p k − 1 ) = ∑ i = 1 k − 1 g ( p i ) G_{k-1}(p_{k-1})=\sum_{i=1}^{k-1}g(p_i) Gk1(pk1)=i=1k1g(pi)也可以预处理。

用埃氏筛求 f f f的前缀和时,应当明确以下几点:

  • 如何快速(一般是线性复杂度)筛出前 n \sqrt{n} n f f f
  • f ( p ) f(p) f(p)的多项式表示
  • 如何快速求出 f ( p c ) f(p^c) f(pc)

明确上述几点之后按顺序实现以下几部分即可:

  1. 筛出 [ 1 , n ] [1, \sqrt{n}] [1,n ]内的质数与前 n \sqrt{n} n f f f值;
  2. f ( p ) f(p) f(p)多项式表示中的每一项筛出对应的 G G G,合并得到 F p r i m e F_{prime} Fprime的所有 O ( n ) O(\sqrt{n}) O(n )有用点值
  3. 按照 F k F_{k} Fk的递推式实现递归,求出 F 1 ( n ) F_{1}(n) F1(n)
P5325【模板】Min_25 筛
const int N = 2e5;
i64 n, lim;

void solve() {
    std::cin >> n;
    lim = sqrt(n);
    std::vector < int > prime, v(N + 10);
    std::vector < MInt > sum1(N + 10), sum2(N + 10);
    for(int i = 2; i <= N; ++i) {
        if(!v[i]) {
            prime.emplace_back(i);
            v[i] = i;
        }
        for(auto x : prime) {
            if(x > N / i || x > v[i]) break;
            v[i * x] = x;
        }
    }
    for(int i = 0; i < prime.size(); ++i) {
        sum1[i + 1] = sum1[i] + prime[i];
        sum2[i + 1] = sum2[i] + MInt(1LL * prime[i] * prime[i]);
    }
    MInt inv2 = MInt(2).inverse(), inv6 = MInt(6).inverse();
    auto f1 = [&](i64 n) -> MInt {
        return MInt(n) * MInt(n + 1) * inv2;
    } ;
    auto f2 = [&](i64 n) -> MInt {
        return MInt(n) * MInt(n + 1) * MInt(2 * n + 1) * inv6;
    } ;
    std::vector < i64 > idpre(N + 10), idsuf(N + 10), w;
    std::vector < std::vector < MInt > > G(2, std::vector < MInt > (N + 10));
    for(i64 l = 1, r; l <= n; l = r + 1) {
        r = n / (n / l);
        w.emplace_back(n / l);
        G[0][w.size()] = f1(n / l) - 1, G[1][w.size()] = f2(n / l) - 1;
        if(n / l <= lim) idpre[n / l] = w.size();
        else idsuf[r] = w.size();
    }
    // std::cerr << '\n';
    auto id = [&](i64 x) -> i64 {
        if(x <= lim) return idpre[x];
        else return idsuf[n / x];
    } ;
    for(int i = 0; i < prime.size(); ++i) {
        int x = prime[i];
        for(int j = 1; j <= w.size() && 1LL * x * x <= w[j - 1]; ++j) {
            G[0][j] -= x * (G[0][id(w[j - 1] / x)] - sum1[i]);
            G[1][j] -= x * x * (G[1][id(w[j - 1] / x)] - sum2[i]);
        }
    }
    // std::cerr << '\n';
    // std::cerr << "123" << '\n';
    auto f = [&](MInt pc) -> MInt {
        return pc * (pc - 1);
    } ;
    auto F = [&](auto self, int k, i64 n) -> MInt {
        if(prime[k] > n) return 0;
        MInt ans = ((G[1][id(n)] - G[0][id(n)]) - (sum2[k] - sum1[k]));
        for(int i = k; i < prime.size() && prime[i] * prime[i] <= n; ++i) {
            for(i64 c = 1, sp = prime[i]; sp <= n / prime[i]; ++c, sp *= prime[i]) {
                ans += f(MInt(sp)) * self(self, i + 1, n / sp) + f(MInt(sp * prime[i]));
            }
        }
        return ans;
    } ;
    std::cout << F(F, 0, n) + 1 << '\n';
}
2024GDCPC 另一个计数问题
题解

注意到,对于所有 x ≤ ⌊ n + 1 2 ⌋ x \le \lfloor \frac{n + 1}{2} \rfloor x2n+1 的结点 x x x x x x 2 x 2x 2x 间有一条边,而 2 x 2x 2x 2 2 2 之间有一条边,因此所有 2 ∼ ⌊ n + 1 2 ⌋ 2 \sim \lfloor \frac{n + 1}{2} \rfloor 22n+1 范围内的结点连通。而对于 x > ⌊ n + 1 2 ⌋ x > \lfloor \frac{n + 1}{2} \rfloor x>2n+1 的结点 x x x x x x 不与 2 ∼ ⌊ n + 1 2 ⌋ 2 \sim \lfloor \frac{n + 1}{2} \rfloor 22n+1 中的结点连通当且仅当 x x x 为素数。因此整个图仅包含若干个单独的素数结点与一个大的连通块。

考虑计算不连通的点对之间的贡献。不难发现,只需要求出所有 > ⌊ n + 1 2 ⌋ > \lfloor \frac{n + 1}{2} \rfloor >2n+1 的素数的和与平方和。使用 Min_25 筛或分块打表均可。

2024杭电多校第2场 1004 a*b problem
题意

求出 b = x 1 t 1 x 2 t 2 x 3 t 3 . . . x k t k , 1 ≤ b ≤ n b=x_1^{t_1}x_2^{t_2}x_3^{t_3}...x_k^{t_k},1\le b\le n b=x1t1x2t2x3t3...xktk,1bn g c d ( x 1 , x 2 , . . . , x k ) = 1 gcd(x_1,x_2,...,x_k)=1 gcd(x1,x2,...,xk)=1时,

( x 1 , x 2 , . . . , x k ) (x_1,x_2,...,x_k) (x1,x2,...,xk)有序对的数量。

题解

f ( n ) f(n) f(n)表示 n = x 1 t 1 x 2 t 2 x 3 t 3 . . . x k t k n=x_1^{t_1}x_2^{t_2}x_3^{t_3}...x_k^{t_k} n=x1t1x2t2x3t3...xktk ( x 1 , x 2 , . . . , x k ) (x_1,x_2,...,x_k) (x1,x2,...,xk)有序对的数量。

即答案为 ∑ i = 1 n f ( i ) \sum_{i=1}^n f(i) i=1nf(i)

如果在这里可以联想到Min_25筛的话,我们可以发现 f ( p c ) f(p^c) f(pc)其实是与 p p p无关的,即 p p p 0 0 0次多项式。

此时我们知道 f ( p ) f(p) f(p)就是 t 1 , t 2 , . . . , t k t_1,t_2,...,t_k t1,t2,...,tk 1 1 1的数量,那么 F p r i m e ( n ) F_{prime}(n) Fprime(n)就是 1 1 1的数量与比 n n n小质数个数的乘积

f ( p c ) f(p^c) f(pc)我们知道每次放进 x i t i x_i^{t_i} xiti中,就是放一个 t i t_i ti的倍数在其中。其实就是关于 c c c的一个完全背包,但是这个完全背包有 g c d ( x 1 , x 2 , . . . , x k ) = 1 gcd(x_1,x_2,...,x_k)=1 gcd(x1,x2,...,xk)=1的限制,这个限制其实就是需要保证每个质数放的时候一定会至少有一个 0 0 0的质量,魔改一下完全背包,加一个是否有放 0 0 0就行。

剩下就变成板子了。

const int N = 2e5;
i64 n, lim;
int m;
MInt f[100001][34][2];

void solve() {
    std::cin >> n >> m;
    std::vector < int > t(m), p(34);
    lim = sqrt(n);
    for(auto &x : t) std::cin >> x, p[x]++;
    if(n == 1) {
        std::cout << "1\n";
        return ;
    }
    std::vector < int > prime, v(N + 10);
    for(int i = 2; i <= N; ++i) {
        if(!v[i]) {
            prime.emplace_back(i);
            v[i] = i;
        }
        for(auto x : prime) {
            if(x > N / i || x > v[i]) break;
            v[i * x] = x;
        }
    }
    MInt inv2 = MInt(2).inverse(), inv6 = MInt(6).inverse();
    std::vector < i64 > idpre(N + 10), idsuf(N + 10), w;
    std::vector < MInt > G(N + 10);
    for(i64 l = 1, r; l <= n; l = r + 1) {
        r = n / (n / l);
        w.emplace_back(n / l);
        G[w.size()] = MInt(n / l) - 1;
        if(n / l <= lim) idpre[n / l] = w.size();
        else idsuf[r] = w.size();
    }
    auto id = [&](i64 x) -> i64 {
        if(x <= lim) return idpre[x];
        else return idsuf[n / x];
    } ;
    for(int i = 0; i < prime.size(); ++i) {
        int x = prime[i];
        for(int j = 1; j <= w.size() && 1LL * x * x <= w[j - 1]; ++j) {
            G[j] -= G[id(w[j - 1] / x)] - i;
        }
    }
    std::vector < MInt > Fprime(w.size() + 1);
    for(int i = 1; i <= w.size(); ++i) {
        Fprime[i] = G[i] * p[1];
    }
    for(int i = 1; i <= m; ++i) {
        for(int j = 0; j <= 33; ++j) {
            f[i][j][0] = f[i][j][1] = 0;
        }
    }
    f[0][0][0] = 1;
    for(int i = 1; i <= m; ++i) {
        for(int j = 0; j <= 33; j += t[i - 1]) {
            if(j == 0) {
                for(int k = 0; k <= 33; ++k) {
                    f[i][k][1] += f[i - 1][k][0] + f[i - 1][k][1];
                }
            } else {
                for(int k = j; k <= 33; ++k) {
                    f[i][k][0] += f[i - 1][k - j][0];
                    f[i][k][1] += f[i - 1][k - j][1];
                }
            }
        }
    }
    auto dp = [&](int c) -> MInt {
        if(c > 33) return 0;
        return f[m][c][1];
    } ;
    auto F = [&](auto self, int k, i64 n) -> MInt {
        if(prime[k] > n) return 0;
        MInt ans = Fprime[id(n)] - k * p[1];
        for(int i = k; i < prime.size() && prime[i] * prime[i] <= n; ++i) {
            for(i64 c = 1, sp = prime[i]; sp <= n / prime[i]; ++c, sp *= prime[i]) {
                ans += dp(c) * self(self, i + 1, n / sp) + dp(c + 1);
            }
        }
        return ans;
    } ;
    std::cout << F(F, 0, n) + 1 << '\n';
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值