其他分享
首页 > 其他分享> > SP20173 题解

SP20173 题解

作者:互联网

题解

提供一个贝尔级数爆拆 \(\sigma_0(n^2)\) 的做法(贝尔级数可见 command_block 的博客 Part. 2)。

设函数 \(f(n)=\sigma_0(n^2)\),不难证明这是一个积性函数:

对于 \(p\bot q\),\(f(p)f(q)=\sigma_0(p^2)\sigma_0(q^2)=\sigma_0((pq)^2)=f(pq)\),且 \(f(1)=1\)。

对于积性函数,就可以写出其贝尔级数:

\[\begin{array}{c} f(1)=1\\ f(p)=\sigma_0(p^2)=3\\ f(p^2)=\sigma_0(p^4)=5\\ \vdots\\ f(p^k)=\sigma_0(p^{2k})=2k+1\\ \vdots \end{array} \]

不难看出是一个等差数列。

记 \(f'(x)\) 为积性函数 \(f(x)\) 的贝尔级数。

\[f'(x)=\sum_{k=0}^{\infty}(2k+1)x^{k} \]

用生成函数基本操作:

\[\begin{aligned} f'(x)&=\sum_{k=0}^\infty(2k+1)x^k\\ f'(x)x&=\sum_{k=1}^\infty (2k-1)x^k\\ f'(x)(1-x)&=1+\sum_{k=1}^\infty 2x^k=g(x)\\ g(x)-g(x)x&=1+x\\ g(x)&=\frac{1+x}{1-x}=f'(x)(1-x)\\ f'(x)&=\frac{1+x}{(1-x)^2} \end{aligned} \]

众所周知,\(\mu^2(x)\) 的贝尔级数为 \(1+x\),\(1(x)\) 的贝尔级数为 \(\frac{1}{1-x}\)。

这里的 \(1(x)\) 指 \(\mu^{-1}(x)\),即 \((1*\mu)(x)=\epsilon(x)\),其中 \(*\) 表示迪利克雷卷积运算。

于是,\(f(x)=\mu^2*1*1\)。记 \(h(x)=\mu^2*1\):

\[\begin{aligned} \sum_{T=1}^nf(T)&=\sum_{T=1}^n\sum_{d\mid T}h(d)\\ &=\sum_{d=1}^nh(d)\lfloor\frac{n}{d}\rfloor \end{aligned} \]

对这个东西数论分块搞一搞,求 \(h(n)\) 的前缀和即可。

于是开始疯狂套用杜教筛:

\[\begin{aligned} \sum_{T=1}^nh(T)&=\sum_{T=1}^n\sum_{d\mid T}\mu^2(d)\\ &=\sum_{d=1}^n\mu^2(d)\lfloor\frac{n}{d}\rfloor \end{aligned} \]

快速求 \(\mu^2(n)\) 的前缀和即可(此步快速求 \(\mu^2(n)\) 前缀和可见)。

\[\begin{aligned} \sum_{T=1}^n\mu^2(T)&=\sum_{T=1}^n\sum_{d^2\mid T}\mu(d)\\ &=\sum_{d=1}^{\sqrt{n}}\mu(d)\lfloor\frac{n}{d^2}\rfloor \end{aligned} \]

关于时间复杂度:

image-20220316193431780.png

预处理处 \(f(n)\)、\(h(n)\)、\(\mu^2(n)\)、\(\mu(n)\) 的前 \(n^{\frac{2}{3}}\) 项的前缀和,加上杜教筛即可,时间复杂度 \(\mathcal O(n^\frac{2}{3})\)。

关于 \(h(n)\) 的线性筛:

\[\begin{aligned} h(p^k) &= (\mu^2*1)(p^k)\\ &= \sum_{i=0}^k\mu^2(p^i)\\ &=\sum_{i=0}^{\min(1, k)}\mu^2(p^i)\\ &=\min(2,k+1) \end{aligned} \]

关于 \(f(n)\) 的线性筛:

\[\begin{aligned} f(p^k) &= (\mu^2*1*1)(p^k)\\ &= (\mu^2*\sigma_0)(p^k)\\ &= \sum_{i=0}^{\min(1,k)}\sigma_0(p^i) \end{aligned} \]

关于 \(\sigma_0(p^k)\),显然有 \(\sigma_0(p^k)=k+1\)。

关于线性筛,在筛的时候若出现 i%prime[j] == 0 的情况,i * prime[j] 的最小质因数幂次必然大于等于 \(2\),可以省去上面 \(\sum\) 中的 \(\min\)。详见代码中 if(i%pr[j] == 0) 部分。

最后注意一下第一个点的时限为 1s,如果仍进行大规模预处理可能会 TLE。

参考实现

// Problem: SP20173 DIVCNT2 - Counting Divisors (square)
// From: Luogu
// URL: https://www.luogu.com.cn/problem/SP20173
// Time: 2022-03-16 19:39
// Author: lingfunny

#include <bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
#define LL long long
#define UL unsigned long long
using namespace std;
using namespace __gnu_pbds;
const int mxz = 7.7e7+100;
unsigned int mu2[mxz];
UL h[mxz], f[mxz];
int pr[(int)1e7], tot, mu[mxz], t, mxn;
LL ask[(int)1e7];
short flg[mxz];
inline int mi(int p, short c) {
	int res = 1;
	while(c) { if(c&1) res *= p; p *= p; c >>= 1; }
	return res;
}
inline void Get() {
	mu[1] = f[1] = h[1] = mu2[1] = 1;
	for(int i = 2; i < mxn; ++i) {
		if(!flg[i]) pr[++tot] = i, mu[i] = -1, flg[i] = 1, h[i] = 2, f[i] = 3;
		for(int j = 1; j <= tot && pr[j] * i < mxn; ++j) {
			int v = i * pr[j];
			if(i%pr[j] == 0) {
				flg[v] = flg[i] + 1;
				// 最小质因数幂次至少为 2
				h[v] = h[v/mi(pr[j], flg[v])]<<1;
				f[v] = f[v/mi(pr[j], flg[v])] * (flg[v]+flg[v]+1);
				break;
			}
			flg[v] = 1;
			mu[v] = -mu[i];
			h[v] = h[i] << 1;
			f[v] = f[i] * 3;
		}
	}
	for(int i = 1; i < mxn; ++i) {
		mu2[i] = mu[i] * mu[i];
		mu2[i] += mu2[i-1];
		h[i] += h[i-1];
		f[i] += f[i-1];
	}
}
gp_hash_table <LL, UL> qh, qf, qm;
inline UL Qm(LL n) {
	if(n < mxn) return mu2[n];
	if(qm.find(n) != qm.end()) return qm[n];
	UL res = 0;
	for(int d = 1; (LL)d*d <= n; ++d)
	res += mu[d] * (n/((LL)d*d));
	qm[n] = res;
	return res;
}
inline UL Qh(LL n) {
	if(n < mxn) return h[n];
	if(qh.find(n) != qh.end()) return qh[n];
	register UL res = 0, pre = 0, cur = 0;
	for(register LL l = 1, r; l <= n; l = r + 1) {
		r = n/(n/l);
		cur = Qm(r);
		res += (cur-pre) * (n/l);
		pre = cur;
	}
	qh[n] = res;
	return res;
}
inline UL Qf(LL n) {
	if(n < mxn) return f[n];
	if(qf.find(n) != qf.end()) return qf[n];
	register UL res = 0, pre = 0, cur = 0;
	for(register LL l = 1, r; l <= n; l = r + 1) {
		r = n/(n/l);
		cur = Qh(r);
		res += (cur-pre) * (n/l);
		pre = cur;
	}
	qf[n] = res;
	return res;
}

signed main() {
	Get();
	scanf("%d", &t);
	LL n = 0;
	for(int i = 1; i <= t; ++i) scanf("%lld", &ask[i]), n = max(n, ask[i]);
	if(n <= 1e4+10) mxn = 1e4+2;
	else mxn = mxz-100;
	Get();
	for(int i = 1; i <= t; ++i) printf("%llu\n", Qf(ask[i]));
	return 0;
}

标签:SP20173,end,int,题解,sum,mu,aligned,sigma
来源: https://www.cnblogs.com/lingfunny/p/16361136.html