P3768 简单的数学题

题意描述

洛谷

求 \(\displaystyle(\sum_{i=1}^{n}\sum_{j=1}^{n} ij \gcd(i,j) )\mod p\)

数据范围: \(n\leq 10^{10}, p 为质数\)。

solution

推了好久才推出来的一道题。

先枚举一下 \(\gcd(i,j)\) 可得:

\(\displaystyle\sum_{d=1}^{n} d\sum_{i=1}^{n}\sum_{j=1}^{n} ij[\gcd(i,j) == d]\)

后面柿子可以提出来一个 \(d\) 变为:

\(\displaystyle \sum_{d=1}^{n}d^3 \sum_{i=1}^{{n\over d}}\sum_{j=1}^{n\over d} ij[\gcd(i,j) == 1]\)

莫比乌斯反演一下可以变为:

\(\displaystyle\sum_{ d=1}^{n} d^3 \sum_{i=1}^{n\over d}\sum_{j=1}^{n\over d}\sum_{p\mid \gcd(i,j)} \mu(p) ij\)

\(\displaystyle\sum_{d=1}^{n} d^3\sum_{p=1}^{n\over d} \mu(p)\sum_{i=1}^{n\over d}\sum_{j=1}^{n\over d} ij[p\mid i,p\mid j]\)

我们观察一下后面的 \(\displaystyle\sum_{i=1}^{n\over d}\sum_{j=1}^{n\over d} ij[p\mid i,p\mid j]\) 这个柿子,你会发现:

\(i\) 的取值可能为: \(\ p,\ 2p,\ 3p,\ 4p....{n\over dp}\)

\(j\) 的取值可能为:\(\ p,2p, \ 3p, \ 4p...{n\over dp}\)

设 \(S(n) = 1+2+3+4....+n\), 那么 \(\displaystyle\sum_{i=1}^{n\over d}\sum_{j=1}^{n\over d} ij[p\mid i,p\mid j] = p^2 S({n\over dp})^2\)。

带入原式可得:

\(\displaystyle\sum_{d=1}^{n} d^3 \sum_{p=1}^{n\over d} \mu(p)p^2 S({n\over dp})^2\)

\(dp\) 化 \(Q\) 可得:

\(\displaystyle\sum_{Q=1}^{n} S({n\over Q})^2 \sum_{d\mid Q} d^3 ({Q\over d})^2 \mu({Q\over d})\)

\(= \displaystyle \sum_{Q=1}^{n} S({n\over Q})^2 \sum_{d\mid Q} Q^2 d \mu({Q\over d})\)

\(= \displaystyle\sum_{Q=1}^{n}S({n\over Q})^2 Q^2 \sum_{d\mid Q} d \mu({Q\over d})\)

然后你会发现 \(\displaystyle \sum_{d\mid Q} d\mu({Q\over d})\) 他是个卷积的形式,由 \(\phi = \mu * id\) 可得: \(\displaystyle \sum_{d\mid Q} d\mu({Q\over d}) = \phi(Q)\), 代入原式可得:

\(\displaystyle\sum_{Q=1}^{n} S({n\over Q}) ^2 Q^2 \phi(Q)\)

前面那个可以拿整除分块来解决,设 \(f(i) = i^2 \phi(i)\) ,现在关键是怎么求出来 \(f(i)\) 的前缀和。

推到这里自己就不会了,看了看题解总算懂了。

\(n \leq 10^{10}\), 所以线性筛又萎了,在这个数据范围下,能做的好像只剩下杜教筛了。

套一下积性函数的柿子 : \(\displaystyle h(n) = \sum_{d\mid n} f(d) g({n\over d})\)

因为 \(f(i)\) 里面有 \(i^2\) ,所以考虑构造 \(g({n\over i})\) 把这一项消掉,那么就 设 \(g(i) = i^2\) 。

根据小学知识可得:\(\displaystyle \sum_{i=1}^{n} g(i) = {n(n+1)(2n+1)\over 2}\), \(g(i)\) 的前缀和就可以 \(O(1)\) 的算出来了。

把 \(g(i)\) 代入原式可得:

\(\displaystyle\ h(n) = \sum_{d\mid n} d^2 \phi(d) ({n\over d})^2\)

\(\displaystyle h(n) = n^2 \sum_{d\mid n} \phi(d)\)

又因为 \(\displaystyle \sum_{d\mid n}\phi(d) = n\), 代入可得: \(h(n) = n^3\)

根据小学知识可得: $\displaystyle\sum_{i=1}^n h(i) = ({n\times (n+1)\over 2})^2 $, 这可也可以 \(O(1)\) 的来求。

然后使用杜教筛就可以在非线性的时间内把 \(f(i)\) 的前缀和算出来了。

最后的答案用数论分块计算一下即可,然后这道题就做完了QWQ。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
#define int long long
using namespace std;
const int N = 1e7+10;
int p,n,tot,inv2,inv6,ans;
int prime[N],phi[N],f[N];
bool check[N];
map<int,int> vis;
inline int read()
{
    int s = 0,w = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
    return s * w; 
}
int ksm(int a,int b)
{
    int res = 1;
    for(; b; b >>= 1)
    {
        if(b & 1) res = res * a % p;
        a = a * a % p;
    }
    return res;
}
void YYCH()
{
    phi[1] = 1;
    for(int i = 2; i <= N-5; i++)
    {
        if(!check[i])
        {
            prime[++tot] = i;
            phi[i] = i-1;
        }
        for(int j = 1; j <= tot && i * prime[j] <= N-5; j++)
        {
            check[i * prime[j]] = 1;
            if(i % prime[j] == 0)
            {
                phi[i * prime[j]] = phi[i] * prime[j] % p;
                break;
            }
            else phi[i * prime[j]] = phi[i] * phi[prime[j]] % p;
        }
    }
    for(int i = 1; i <= N-5; i++) f[i] = i * i % p * phi[i] % p;
    for(int i = 1; i <= N-5; i++) f[i] = (f[i] + f[i-1]) % p;
}
int sqr(int x)
{
	x %= p; 
	return x * (x+1) % p * (2 * x % p + 1) % p * inv6 % p;
}
int Sum(int n)
{
    if(n == 0) return 0;
    n %= p;//这里 n*n 直接算的话会炸long long 所以要预先模一下
    int tmp = n * (n + 1) % p * inv2 % p;
    return tmp * tmp % p;
}
int get(int n)
{
    if(n <= N-5) return f[n];
    if(vis[n]) return vis[n];
    int res = Sum(n);
    for(int l = 2, r; l <= n; l = r+1)
    {
        r = min(n,n/(n/l));
        res -= get(n/l) * ((sqr(r)-sqr(l-1) % p + p) % p) % p;
	res = (res + p) % p; 
    }
    vis[n] = (res % p + p) % p;
    return vis[n];
}
signed main()
{
    p = read(); n = read(); YYCH(); inv2 = ksm(2,p-2); inv6 = ksm(6,p-2);
    for(int l = 1, r; l <= n; l = r+1)
    {
        r = min(n,n/(n/l));
        ans = (ans + Sum(n/l) * ((get(r)-get(l-1) + p) % p) % p) % p;
    }
    printf("%lld\n",ans);
    return 0;
}
上一篇:数值分析 - 对流项的离散


下一篇:[模板]杜教筛