数论2&莫&杜

积性函数:

积性函数定义ok

积性函数指对于所有互质的整数(a)(b)有性质(f(ab)=f(a)f(b))的数论函数

除数函数?

莫比乌斯函数(mu)ok

[phi(i) = egin{cases} 1, & i==1 \ (-1)^k, & i == prod_{i=1}^{k}{p_i^1 {p}, p_i为所有质因子 \ 0, & otherwise end{cases} ]

为什么是积性函数?

对任意(a,b,gcd(a,b)=1), (ab)的质因子集合可以不重不漏分到(a,b)的质因子集合中

分类讨论一下,满足定义

欧拉函数(phi)ok

小于等于(n)的数中与(n)互质的数的数目

通式:

[phi(n)=n*prod_{i=1}^{k}(1-frac{1}{p_i})\ ]

通式的意义:把他展开, 相当于做容斥, 筛除的所有(n)因数

为什么是积性函数?

对任意(a,b,gcd(a,b)=1), (a,b)没有不含有相同的(p), 直接带入通式得证

反正关于欧拉函数的东西盯着这个通式就好了

幂函数(Id)ok

(id_k(n)=n^k)

(id(n)=id_1(n)=n)

显然是积性函数

单位函数(epsilon)ok

(epsilon(n)=[n=1])

显然是积性函数

线性筛

核心:保证每个数只被他最小的质数筛到一次

int tot;
bool vis[MAXN];
int p[MAXN], phi[MAXN], mu[MAXN];
void filter()
{
	phi[1] = mu[1] = 1;
	for (int i = 2; i <= n; ++ i)
		{
			if (!vis[i]) p[++ tot] = i, phi[i] = i - 1, mu[i] = -1;
			for (int j = 1; j <= tot && i * p[j] <= n; ++ j)
				{
					vis[i * p[j]] = true;
					if (i % p[j] == 0)
						{
							phi[i * p[j]] = phi[i] * p[j]; mu[i * p[j]] = 0;
                        //没有增加质因子, 结合phi的通式可得
							break;
						}
					else 
						{
							phi[i * p[j]] = phi[i] * phi[p[j]];
							mu[i * p[j]] = -mu[i];
						}
				}
			printf("%d %d
", mu[i], phi[i]);
		}
}

Dirichlet卷积

[(f*g)(n)=sum_{d|n}f(d)g(frac{n}{d}) ]

交换律 (f ∗ g = g ∗ f)
结合律 ((f ∗ g) ∗ h = f ∗ (g ∗ h))
分配律 (f ∗ (g + h) = f ∗ g + f ∗ h)
单位元 (f ∗ ϵ = f)

(f,g) 均为积性函数,则 (f*g) 也是积性函数

证明:

对任意(a,b,gcd(a,b)=1), (ab)的质因子集合可以不重不漏分到(a,b)的质因子集合中

((f*g)(ab) = sum_{d|ab}f(d)g(frac{ab}{d}))

(d=d_a*d_b), (d_a,d_b)分别由(a,b)的因子组成, 显然组成的方式唯一, 并且(d)唯一分解成(d_a,d_b)

[egin{aligned} (f*g)(ab)&=sum_{d_a|a, d_b|b}f(d_a)f(d_b)g(frac{a}{d_a})g(frac{b}{d_b})\ &=sum_{d_a|a, d_b|b}f(d_a)g(frac{a}{d_a})*f(d_b)g(frac{b}{d_b})\ &=(f*g)(a)*(f*g)(b) end{aligned} ]

已知(f,g),(O(nlog_2^n))((f*g))

for (int i = 1; i * i <= n; ++ i)
{
    (f*g)[i*j] += f[i] * g[i];
    for (int j = i + 1; i * j <= n; ++ j)
        (f*g)[i*j] += f[i] * g[j] + f[j] * g[i];
}

不会证


常见数论函数

(sigma(n))表示整数(n)的所有正因数的和

( au(n))表示整数(n)的所有正因数的个数

(Id(i)=i)

以及前面的一些积性函数

常见狄利克雷卷积及其证明

(epsilon = mu *1)

证明:

(n)含有多个相同质因子或(=1)是显然成立

考虑(n=p_1*p_2*...*p_k), (p_i)都是不同质因子

[egin{aligned} epsilon(n) & = sum_{d|n}mu(d) \ & = sum_{i=1}^{k}inom{k}{i}*(-1)^k \ end{aligned} ]

由于((x+y)^k=sum x^iy^{k-i}*inom{k}{i}), 带入(x=-1, y=1), 凑进去

[egin{aligned} epsilon(n)&=sum_{i=1}^{k}0^k\ &= egin{cases} 1, & k=0 so n=1 \ 0, & otherwise end{cases} end{aligned} ]


(sigma = Id*1)

( au=1*1)

显然


(phi = mu * Id)

证明:

[egin{aligned} phi(n) & = sum_{d|n}mu(d)id(frac{n}{d}) \ & = 1 cdot n + sum_{d=prod p}mu(d)id(frac{n}{d}) + 0cdot (...)\ & = n + sum_{i=1}^{k}(-1)^k*n*frac{1}{prod{p}} \ & = n * prod_{i=1}^{k}(1-frac{1}{p_i}) end{aligned} ]


(phi * 1= Id)

上面一个等式两边同乘以(1)


莫比乌斯Van演

定理:(epsilon = mu * 1)

若函数 (f, g) 满足
(f(n) = sum_{d|n}g(d))

(g(n) = sum_{d|n}mu(d)f(frac{n}{d}) = sum_{d|n}mu(frac{n}{d})f(d))

证明:$

(f = g*1 longleftrightarrow mu * f = g) $

左式同乘以(mu), 右式同乘以(1)

常用:
运用这个卷积:
(epsilon = mu * 1)(sum_{d|n}mu(d) = 1)

([gcd(i, j) == 1] = sum_{k | gcd(i,j)} mu(k))

例题:

NOI2015寿司

BZOJ1257: CQOI2007余数之和

题意:
(n, k(le10^9)), 求(sum_{i=1}^{n}(k mod i))

Sol:
(sum_{i=1}^{n}(k mod i) = sum_{i=1}^{n}(k - k / i * i) = nk - sum_{i=1}^{n}(k/i)*i)

BZOJ1101: POI2007Zap

(T) 组询问,(1 ≤ T, n, m , d≤ 50000)

[sum_{x=1}^{n}sum_{y=1}^{m}[gcd(x,y)=d] ]

相当于求

[sum_{x=1}^{n/d}sum_{y=1}^{m/d}[gcd(x,y)=1] ]

n /= d, m /= d 根据(epsilon = mu * 1),即求

[egin{aligned} & = sum_{i=1}^{n}sum_{j=1}^{m}sum_{d|gcd(i,j)}mu(d) \ & = sum_{i=1}^{n}sum_{j=1}^{m}sum_{d|i,d|j}mu(d) \ & = sum_dmu(d)lfloorfrac{n}{d} floorlfloorfrac{m}{d} floor end{aligned} ]

除法分块(O(sqrt{n}))

BZOJ2154: Crash的数字表格

(1le n, mle10^7), 求

[sum_{i=1}^{n}sum_{j=1}^{m} lcm(i,j) ]

(i*j=gcd(i,j) * lcm(i,j))

[egin{aligned} &= sum_{i=1}^{n}sum_{j=1}^{m}frac{i*j}{gcd(i,j)} \ &= sum_{i=1}^{n}sum_{j=1}^{m}frac{i}{gcd(i,j)}frac{j}{gcd(i,j)}gcd(i,j) \ &= sum_{g}gsum_{i=1}^{n/g}sum_{j=1}^{m/g}i*j*[gcd(i,j)=1] \ &= sum_{g}gsum_{i=1}^{n/g}sum_{j=1}^{m/g}i*j*sum_{d|gcd(i,j)}mu(d) \ &= sum_{g}gsum_{i=1}^{n/g}sum_{j=1}^{m/g}i*j*sum_{d|i,d|j}mu(d) \ &= sum_{g}gsum_{d}sum_{i=1}^{n/gd}sum_{j=1}^{m/gd}i*d*j*d*mu(d) \ &= sum_{gd}gdsum_{i=1}^{n/gd}sum_{j=1}^{m/gd}i*j*d*mu(d) \ end{aligned} ]

(p=g*d)

[egin{aligned} &= sum_{p}p*sum_{d|p}d*mu(d)sum_{i=1}^{n/p}sum_{j=1}^{m/p}ij end{aligned} ]

完了,然后怎么做?

大爷xyyxyyx说: (F(p)=sum_{d|p}d*mu(d)*p)是积性函数

为什么?

(a,b,gcd(a,b)=1,d=da*db,da|a,db|b)

[F(ab)=sum_{da|a,db|b}da*mu(da)*db*mu(db)*a*b ]

好了, 然后(O(n))筛?然后暴力(O(n))求答案?

观察(F(i))的式子, 套用线性筛:

  • (i)为质数: (F(i)=(1*mu(1)+i*mu(i))*i)
  • 用已经筛出来的质数(p[j])去筛(i*p[j])
    • (imod p[j]!=0), 互质!(F(i*p[j])=F(i)*F(p[j]))
    • (i mod p[j] == 0),考虑对比(F(i)),新加入的因数必须含有(p^2), 而这样的因数(mu{})是等于0的!那么直接(F(i*p[j])=F(i)*p[j])

然后少写了一个(mod), WA了,然后又T了

整出分块!!注意到在一段区间里((n/p, m/p))是不变的, 所以可以对(F)直接区间求和(前缀和实现)

//空间注意一点
#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
const int MAXN = 1e7 + 10;
const LL MOD = 20101009;

int n, m;
LL ans;

int tot;
bool vis[MAXN];
int mu[MAXN], p[664590];
LL f[MAXN];
int sum[MAXN], sumf[MAXN];
void filter()
{
    mu[1] = sumf[1] = f[1] = sum[1] = 1;
	LL tmp1 = 0;
    for (int i = 2; i <= m; ++ i)
        {
            tmp1 = 1LL * i * (i + 1) / 2 % MOD;
			sum[i] = tmp1;
            if (!vis[i]) mu[i] = -1, p[++ tot] = i, f[i] = 1LL * (1 + i * mu[i] % MOD + MOD) * i % MOD;
            for (int j = 1; j <= tot && i * p[j] <= m; ++ j)
                {
                    vis[i * p[j]] = true;
                    if (i % p[j] == 0) { mu[i * p[j]] = 0; f[i * p[j]] = f[i] * p[j] % MOD; break; }
                    else mu[i * p[j]] = -mu[i], f[i * p[j]] = f[i] * f[p[j]] % MOD;
                }
            sumf[i] = (sumf[i - 1] + f[i]) % MOD;
        }
}

int main()
{
    scanf("%d%d", &n, &m);
    if (n > m) swap(n, m);
    filter();
    for (int i = 1; i <= n; )
        {
            int r = min(n, min(n / (n / i), m / (m / i)));
            (ans += sum[n / i] % MOD * sum[m / i] % MOD * (sumf[r] - sumf[i - 1] + MOD) % MOD) %= MOD;
            i = r + 1;
        }
    printf("%lld
", ans);
    return 0;
}

PE530: GCD of Divisors

Let f(n) be the sum of the greatest common divisor of d and n/d over all positive divisors d of n, that is (f(n)=displaystylesumlimits_{d|n}\, ext{gcd}(d,frac n d))

Let F be the summatory function of f, that is (F(k)=displaystylesumlimits_{n=1}^k \, f(n))

You are given that (F(10)=32) and (F(1000)=12776.)

Find (F(1015)).

提交答案题

[F(n) = sum_{i=1}^{n}sum_{d|i}{gcd(d, frac{i}{d})} ]

相当于枚举(i), 并将(i)分解成两个数的乘积, 求所有这样的(gcd)的和

等价于枚举两个数, 他们乘积(le n), 求他们(gcd)的乘积

所以:

[egin{aligned} F(n)&=sum_{i = 1}^{n}sum_{j=1}^{n/i}{gcd(i,j)} \ &=sum_ggsum_isum_j[gcd(i,j)==1][i*g*j*gle n] end{aligned} ]

注意不能像以前那样把两个(sum{})的上界除以(g)

从而认为(i*jle n/g)

因为两个(sum{})是有关联的,只有当第一个确定时,才能枚举第二个, 如果这么做的话相当于同时枚举两个

例如(i*jle n*n/i)显然不对

那么继续

[egin{aligned} F(n) &= sum_ggsum_isum_jsum_{d|i,d|j}mu(d)*[i*j*g^2le n] \ &= sum_ggsum_dmu(d)sum_isum_j[i*jlefrac{n}{g^2*d^2}] \ end{aligned} ]

考虑把(g*d)并在一起, 然后康康这个和什么卷积比较像

[p = gd\ phi(x)=sum_{d|x}Id(x)*mu(frac{n}{x}) \ ]

于是就化简成了

[F(n)=sum_pphi(p)*sum_isum_j[i*jlefrac{n}{p^2}] ]

什么,要求(10^{15})?不会炸空间吗?

注意后面(lfloor frac{n}{p^2} floor), 可以缩小到(sqrt{n})

那么枚举(p), 然后每次单独分块求就好了

[F(n)=phi(p)*sum_ilfloorfrac{n}{p^2i} floor ]

复杂度呢?前半个(O(sqrt{n})), 后半个(O(ln_n))?不会证...

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
const int MAXN = 32e6 + 10;
const LL MOD = 20101009;

LL n;
LL ans;

int tot;
bool vis[MAXN];
LL p[MAXN], phi[MAXN];
LL f[MAXN];
void filter()
{
    phi[1] = 1;
    for (int i = 2; i < MAXN; ++ i)
        {
            if (!vis[i]) p[++ tot] = i, phi[i] = i - 1;
            for (int j = 1; j <= tot && i * p[j] < MAXN; ++ j)
                {
                    vis[i * p[j]] = true;
                    if (i % p[j] == 0) { phi[i * p[j]] = phi[i] * p[j]; break; }
                    else phi[i * p[j]] = phi[i] * phi[p[j]];;
                }
        }
}

LL calc(LL x)
{
	LL ret = 0;
	for (LL i = 1; i <= x; )
		{
			LL r = min(x / (x / i), x);
			ret += (r - i + 1) * (x / i);
			i = r + 1;
		}
	return ret;
}

int main()
{
    scanf("%lld", &n);
	n = 1e15;
    filter();
    for (LL i = 1; i * i <= n; ++ i)
        {
			ans += phi[i] * calc(n / (i * i));
        }
    printf("%lld
", ans);
    return 0;
}

杜教筛

基本

目的:求(f(i))的前缀和

套路:构造(h=g*f)

[egin{aligned} sum_{i=1}^{n}h(i)&=sum_{i=1}^{n}sum_{d|i}g(d)*f(frac{d}{i}) \ end{aligned} ]

即等同于枚举两个因数,他们乘积(le n),计算他们(g)(f)的乘积的和

[egin{aligned} &=sum_{d=1}^{n}g(d)sum_{i=1}^{lfloorfrac{n}{d} floor}f({i}) \ end{aligned} ]

(S(n)=sum f(i))

[egin{aligned} sum_{i=1}^{n}h(i)&=sum_{d=1}^{n}g(d)S(lfloorfrac{n}{d} floor) \ sum_{i=1}^{n}h(i)&=g(1)*S(n)+sum_{d=2}^{n}g(d)S(lfloorfrac{n}{d} floor) \ g(1)*S(n)&=sum_{i=1}^{n}h(i)-sum_{d=2}^{n}g(d)S(lfloorfrac{n}{d} floor)\ end{aligned} ]

所以只要凑出方便的(h, g)就可以套用最后一行式子了

[g(1)*S(n)=sum_{i=1}^{n}h(i)-sum_{d=2}^{n}g(d)S(lfloorfrac{n}{d} floor) ]

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

(epsilon = mu * 1, h=epsilon,g=1)

[S(n)=1-sum_{i=2}^{n}S(lfloorfrac{n}{i} floor) ]

(sum_{i=1}^{n}phi(i))

(Id=phi*1, h=Id, g=1)

[S(n)=frac{n*(n+1)}{2}-sum_{i=2}^{n}S(lfloorfrac{n}{i} floor) ]

先看一道例题

例题BZOJ3944: Sum

(T(le 10))组数据, (N(le 2^{31}-1)), 求(sum_{i=1}^{n}mu(i), sum_{i=1}^{n}phi(i))

两个长得很像可以一起做, (lfloorfrac{n}{i} floor)可以整除分块

递归实现, 但是要先预先筛一部分, 不然会(T), 记忆化搜索用(map)记录

#include <cstdio>
#include <map>

using namespace std;
typedef long long LL;
typedef pair<int, LL> PIL;
#define mkpr make_pair
const int MAXN = 5e6 + 2;

inline LL in()
{
    LL x = 0, flag = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') flag = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
    return x * flag;
}

int n;

int tot;
bool vis[MAXN];
int p[348516], mu[MAXN]; //348513
LL phi[MAXN];
void filter()
{
	phi[1] = mu[1] = 1;
	for (int i = 2; i < MAXN; ++ i)
		{
			if (!vis[i]) { mu[i] = -1, phi[i] = i - 1, p[++ tot] = i; }
			for (int j = 1; j <= tot && i * p[j] < MAXN; ++ j)
				{
					vis[i * p[j]] = true;
					if (i % p[j] == 0)
						{ mu[i * p[j]] = 0, phi[i * p[j]] = phi[i] * p[j]; break; }
					else 
						mu[i * p[j]] = -mu[i], phi[i * p[j]] = phi[i] * phi[p[j]];
				}
		}
	for (int i = 2; i < MAXN; ++ i) mu[i] += mu[i - 1], phi[i] += phi[i - 1];
}


map <LL, PIL> f; //92680
PIL solve(LL x) // Smu[x] = 1 - [2, n]Smu[x / i], 
{
	if (x < MAXN) return mkpr(mu[x], phi[x]);
	if (f.count(x)) return f[x];
	int mu = 1; LL phi = x * (x + 1) / 2;
	for (LL i = 2, nex = i; i <= x; i = nex + 1)
		{
			nex = x / (x / i);
			PIL val = solve(x / i);
			mu -= (nex - i + 1) * val.first;
			phi -= (nex - i + 1) * val.second; 
		}
	return f[x] = mkpr(mu, phi);
}

int main()
{
	filter();
	//	printf("%d
", tot);
	int Test = in();
	while (Test --)
		{
			n = in();
			PIL ans = solve(n);
			printf("%lld %d
", ans.second, ans.first);
		}
	return 0;
}

复杂度

不会证, 据说预处理(n^{frac{2}{3}}), 复杂度为(O(n^{frac{2}{3}}))

原文地址:https://www.cnblogs.com/Kuonji/p/12075836.html