牛客练习赛69 F.解方程(莫比乌斯反演 + 迪利克雷卷积性质 + 欧拉筛)

牛客练习赛69 F.解方程(莫比乌斯反演 + 迪利克雷卷积性质 + 欧拉筛)_第1张图片


n , p , q n,p,q n,p,q 均为 1 0 7 10^7 107,这个规模下可以考虑求出所有的 f ( i ) f(i) f(i),题目给出的式子很明显要用莫比乌斯反演,因为莫比乌斯反演的形式为:

形式一:设 F ( n ) = ∑ d ∣ n f ( d ) F(n) = \displaystyle\sum_{d | n} f(d) F(n)=dnf(d) ,则有 f ( n ) = ∑ d ∣ n μ ( d ) ∗ F ( n d ) = ∑ d ∣ n F ( d ) ∗ μ ( n d ) f(n) = \displaystyle\sum_{d | n}\mu(d)*F(\frac{n}{d}) = \sum_{d | n}F(d)*\mu(\frac{n}{d}) f(n)=dnμ(d)F(dn)=dnF(d)μ(dn)

形式二:设 F ( n ) = ∑ n ∣ d f ( d ) F(n) = \displaystyle\sum_{n | d} f(d) F(n)=ndf(d) ,则有 f ( n ) = ∑ n ∣ d F ( d ) ∗ μ ( d n ) f(n) = \displaystyle\sum_{n | d} F(d)*\mu(\frac{d}{n}) f(n)=ndF(d)μ(nd)

接下来开始推公式:

σ ( n ) = ∑ i ∣ n i = ∑ i ∣ n I d ( i ) = ( I d ∗ I ) ( n ) \sigma(n)=\displaystyle\sum_{i|n}i=\sum_{i|n}Id(i)=(Id*I)(n) σ(n)=ini=inId(i)=(IdI)(n)
显然同样可以得到 σ p ( n ) = ∑ i ∣ n i = ∑ i ∣ n I d p ( i ) = ( I d p ∗ I ) ( n ) \sigma_p(n)=\displaystyle\sum_{i|n}i=\sum_{i|n}Id_p(i)=(Id_p*I)(n) σp(n)=ini=inIdp(i)=(IdpI)(n)

那么有 f ∗ I d p ∗ I = I d q ∗ I f*Id_p*I=Id_q*I fIdpI=IdqI,左右约掉函数 I I I,得到 f ∗ I d p = I d q f*Id_p = Id_q fIdp=Idq

∑ i ∣ n f ( i ) ( n i ) p = n q \sum_{i|n}f(i)(\frac{n}{i})^p=n^q inf(i)(in)p=nq ∑ i ∣ n f ( i ) i p = n q − p \sum_{i|n}\frac{f(i)}{i^p}=n^{q-p} inipf(i)=nqp

套用莫比乌斯反演可以得到: f ( n ) n p = ∑ i ∣ n μ ( i ) ∗ ( n i ) q − p \frac{f(n)}{n^p}=\sum_{i|n}\mu(i)*(\frac{n}{i})^{q-p} npf(n)=inμ(i)(in)qp f ( n ) = n p ∑ i ∣ n μ ( i ) ∗ ( n i ) q − p = n q ∗ ∑ i ∣ n μ ( i ) i q − p f(n)=n^p\sum_{i|n}\mu(i)*(\frac{n}{i})^{q-p}=n^q*\sum_{i|n}\frac{\mu(i)}{i^{q-p}} f(n)=npinμ(i)(in)qp=nqiniqpμ(i)

迪利克雷卷积的性质告诉我们, f ( n ) n p \frac{f(n)}{n^p} npf(n) 是一个积性函数,且 n p n^p np 是一个积性函数,那么 f ( n ) f(n) f(n) 一定也是一个积性函数,积性函数乘积性函数得到的也是积性函数。

考虑用欧拉筛来筛出 f ( n ) f(n) f(n),考虑 f ( d ) , f ( d k ) f(d),f(d^k) f(d)f(dk)

f ( d ) f(d) f(d) 显然等于 d q ∗ ( 1 − 1 d q − p ) d^q*(1-\displaystyle\frac{1}{d^{q-p}}) dq(1dqp1)
f ( d k ) = d k q ∗ ( 1 − 1 d q − p ) f(d^k) = d^{k q}*(1-\displaystyle\frac{1}{d^{q-p}}) f(dk)=dkq(1dqp1)

直接欧拉筛,这里不免要求一下质数的幂次,根据质数的分布性质, n n n 以内大约有 n log ⁡ n \frac{n}{\log n} lognn 个质数,对这些质数求快速幂的复杂度为 log ⁡ n \log n logn,时间复杂度为 O ( n log ⁡ n ∗ log ⁡ n = n ) O(\frac{n}{\log n} * \log n=n) O(lognnlogn=n)


代码:

#include
using namespace std;
const int maxn = 1e7 + 10;
const int mod = 998244353;
bool ispri[maxn];
int n, p, q, f[maxn], pri[maxn], val[maxn];
int fpow(int a,int b) {
     
	int r = 1;
	while (b) {
     
		if (b & 1) r = 1ll * r * a % mod;
		b >>= 1;
		a = 1ll * a * a % mod;
	}
	return r;
}
int calc(int d) {
     
	int v = p - q;
	if (v < 0) return (1 - fpow(fpow(d,-v),mod - 2) + mod) % mod;
	else return (1 - fpow(d,v) + mod) % mod;
}
void sieve(int n) {
     
	ispri[0] = ispri[1] = true; pri[0] = 0; f[1] = 1;
	for (int i = 2; i <= n; i++) {
     
		if (!ispri[i]) {
     
			pri[++pri[0]] = i;
			val[i] = fpow(i,q);
			f[i] = 1ll * val[i] * calc(i) % mod;
		}
		for (int j = 1; j <= pri[0] && i * pri[j] <= n; j++) {
     
			ispri[i * pri[j]] = true;
			if (i % pri[j] == 0) {
     
				f[i * pri[j]] = 1ll * f[i] * val[pri[j]] % mod;
				break;
			} else {
     
				f[i * pri[j]] = 1ll * f[i] * f[pri[j]] % mod;
			}
		}
	}
	/*for (int i = 1; i <= n; i++)
		f[i] = 1ll * f[i] * fpow(i,q) % mod; */
}
int main() {
     
	scanf("%d%d%d",&n,&p,&q);
	sieve(n);
	int res = 0;
	for (int i = 1; i <= n; i++)
		res = res ^ f[i];
	printf("%d\n",res);
	return 0;
}

你可能感兴趣的:(欧拉筛,莫比乌斯反演,迪利克雷卷积,积性函数)