洛谷P6222 简单题
题意
求
$$\sum_{i=1}^n\sum_{j=1}^n(i+j)^k\gcd(i,j)\mu^2(\gcd(i,j))$$
$n\le 10^6$
Sol
还是按照套路推式子
$$\sum_{i=1}^n\sum_{j=1}^n(i+j)^k\gcd(i,j)\mu^2(\gcd(i,j))$$
枚举$\gcd(i,j)$
$$=\sum_{d=1}^nd\mu^2(d)\sum_{i=1}^{\lfloor\frac nd\rfloor}\sum_{j=1}^{\lfloor\frac nd\rfloor}d^k(i+j)^k[\gcd(i,j)=1]$$
$$=\sum_{d=1}^nd^{k+1}\mu^2(d)\sum_{i=1}^{\lfloor\frac nd\rfloor}\sum_{j=1}^{\lfloor\frac nd\rfloor}(i+j)^k\sum_{x|\gcd(i,j)}\mu(x)$$
枚举$x$
$$=\sum_{d=1}^nd^{k+1}\mu^2(d)\sum_{x=1}^{\lfloor\frac nd\rfloor}x^k\mu(x)\sum_{i=1}^{\lfloor\frac n{dx}\rfloor}\sum_{j=1}^{\lfloor\frac n{dx}\rfloor}(i+j)^k$$
令$S(n)=\sum_{i=1}^n\sum_{j=1}^n(i+j)^k$,则原式为
$$=\sum_{d=1}^nd^{k+1}\mu^2(d)\sum_{x=1}^{\lfloor\frac nd\rfloor}x^k\mu(x)S(\lfloor\frac n{dx}\rfloor)$$
$$=\sum_{d=1}^n\sum_{x=1}^{\lfloor\frac nd\rfloor}d^{k+1}x^k\mu(x)\mu^2(d)\cdot S(\lfloor\frac n{dx}\rfloor)$$
令$dx=T$,枚举$T$
$$=\sum_{T=1}^nT^kS(\lfloor\frac nT\rfloor)\sum_{d|T}d\mu(\frac Td)\mu^2(d)$$
考虑如何快速筛出$S(n)$的前缀和与$T^k\sum_{d|T}d\mu(\frac Td)\mu^2(d)$
先看$S(n)$的定义式
$$S(n)=\sum_{i=1}^n\sum_{j=1}^n(i+j)^k$$
所以对于数$x\in[1,n]$,$x^k$会出现$x-1$次,分别为$1+(x-1),2+(x-2),...,(x-1)+1$
同理,对于数$x\in[n+1,2n]$,$x^k$会出现$2n-x+1$次
我们设$F(n)=\sum_{i=1}^ni^k,G(n)=\sum_{i=1}^nF(i)$,则$S(n)=\sum_{i=n+1}^{2n}F(i)-\sum_{i=1}^nF(i)=G(2n)-2G(n)$
所以先筛出所有$i^k$的值,两次前缀和求出$G(n)$即可
对于$T^k\sum_{d|T}d\mu(\frac Td)\mu^2(d)$来说,$T^k$已经在上一步筛好,设剩下的为$f(x)=\sum_{d|T}d\mu(\frac Td)\mu^2(d)$
观察其形式,发现是一堆积性函数的卷积,故该函数为积性函数,可以线筛。
当枚举到数$n$重复的约数时,我们设该数为$p$,且$p^k|n,p^{k+1}\nmid n$
那么当$k=0$时,$f(1)=1$
当$k=1$时,$f(p)=p-1$
当$k=2$时,$f(p^2)=-p$
当$k\ge 3$时,$\frac Td$与$d$中必有平方因子,故$f(p^k)=0$
最后整除分块即可。
#include <bits/stdc++.h> using namespace std; #define int unsigned int int F[20000005], G[20000005], S[20000005], f[20000005], sum[20000005], prime[20000005], vis[20000005], tot = 0, n, k; int ksm(int a, int b) { int res = 1; while (b) { if (b & 1) res = res * a; a = a * a; b >>= 1; } return res; } void prework(int n) { F[1] = f[1] = 1; for (int i = 2; i <= n; i++) { if (!vis[i]) { prime[++tot] = i; f[i] = i - 1; F[i] = ksm(i, k); } for (int j = 1; j <= tot && i * prime[j] <= n; j++) { vis[i * prime[j]] = 1; F[i * prime[j]] = F[i] * F[prime[j]]; if (i % prime[j] == 0) { int q = i / prime[j]; if (q % prime[j]) f[i * prime[j]] = f[q] * (-prime[j]); break; } f[i * prime[j]] = f[i] * f[prime[j]]; } } for (int i = 2; i <= n; i++) { f[i] = f[i - 1] + f[i] * F[i]; F[i] += F[i - 1]; } for (int i = 2; i <= n; i++) F[i] += F[i - 1]; } int Calc(int x) { return F[x << 1] - (F[x] << 1); } signed main() { int T, N; cin >> T >> N >> k; prework(N * 2); while (T--) { int ans = 0; cin >> n; for (int l = 1, r; l <= n; l = r + 1) { r = (n / (n / l)); ans += (f[r] - f[l - 1]) * Calc(n / l); } cout << ans << endl; } }