洛谷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;
    }
}
Code

 

posted @ 2020-06-02 21:58  verjun  阅读(191)  评论(0编辑  收藏  举报