【luogu】简单的数学题(莫比乌斯反演、杜教筛)

题意

给出 n n n p , ( n ≤ 1 0 10 ) p,(n \le 10^{10}) p,(n1010),求

∑ i = 1 n ∑ j = 1 n i ⋅ j ⋅ g c d ( i , j )    m o d    p \sum_{i=1}^{n}\sum_{j=1}^{n}i \cdot j \cdot gcd(i,j) \; mod \; p i=1nj=1nijgcd(i,j)modp

思路

准备好莫比乌斯反演,开始推式子,枚举 g c d gcd gcd

∑ d = 1 n d 3 ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ n d ⌋ i j [ g c d ( i , j ) = 1 ] \sum_{d=1}^{n}d^3 \sum_{i=1}^{\lfloor \frac{n}{d} \rfloor}\sum_{j=1}^{\lfloor \frac{n}{d} \rfloor}ij[gcd(i,j)=1] d=1nd3i=1dnj=1dnij[gcd(i,j)=1]

看到 g c d gcd gcd就可以用 ϵ = I ∗ μ \epsilon = I*\mu ϵ=Iμ

[ g c d ( i , j ) = 1 ] = ∑ d ∣ i , d ∣ j μ ( d ) [gcd(i, j) = 1] = \sum_{d|i,d|j}\mu(d) [gcd(i,j)=1]=di,djμ(d)

所以

∑ d = 1 n d 3 ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ n d ⌋ i j ∑ k ∣ i , k ∣ j μ ( k ) \sum_{d=1}^{n}d^3 \sum_{i=1}^{\lfloor \frac{n}{d} \rfloor}\sum_{j=1}^{\lfloor \frac{n}{d} \rfloor}ij\sum_{k|i,k|j}\mu(k) d=1nd3i=1dnj=1dnijki,kjμ(k)

再枚举 k k k

∑ d = 1 n d 3 ∑ k = 1 ⌊ n d ⌋ μ ( k ) ⋅ k 2 ∑ i = 1 ⌊ n d k ⌋ ∑ j = 1 ⌊ n d k ⌋ i j \sum_{d=1}^{n}d^3 \sum_{k=1}^{\lfloor \frac{n}{d} \rfloor}\mu(k)\cdot k^2 \sum_{i=1}^{\lfloor \frac{n}{dk} \rfloor}\sum_{j=1}^{\lfloor \frac{n}{dk} \rfloor}ij d=1nd3k=1dnμ(k)k2i=1dknj=1dknij

后面那两个求和是前缀和,令 s u m ( n ) = ∑ i = 1 n i sum(n)=\sum_{i=1}^{n}i sum(n)=i=1ni,则

∑ d = 1 n d 3 ∑ k = 1 ⌊ n d ⌋ μ ( k ) ⋅ k 2 ⋅ s u m ( ⌊ n d k ⌋ ) 2 \sum_{d=1}^{n}d^3 \sum_{k=1}^{\lfloor \frac{n}{d} \rfloor}\mu(k)\cdot k^2 \cdot sum(\lfloor \frac{n}{dk} \rfloor)^2 d=1nd3k=1dnμ(k)k2sum(dkn)2

看到了两个整除,但是暂时还没有办法分块,所以继续

发现假如我们令 T = d k T=dk T=dk然后枚举 T T T,可以少掉一个求和,多出一个枚举因子,有可能有奇怪的卷积形式出现

∑ T = 1 n s u m ( ⌊ n T ⌋ ) 2 ∑ k ∣ T μ ( k ) ⋅ k 2 ⋅ ( T k ) 3 \sum_{T=1}^{n}sum(\lfloor \frac{n}{T} \rfloor)^2\sum_{k|T}\mu(k) \cdot k^2 \cdot (\frac{T}{k})^3 T=1nsum(Tn)2kTμ(k)k2(kT)3

化简

∑ T = 1 n s u m ( ⌊ n T ⌋ ) 2 ⋅ T 2 ∑ k ∣ T μ ( k ) ⋅ T k \sum_{T=1}^{n}sum(\lfloor \frac{n}{T} \rfloor)^2 \cdot T^2 \sum_{k|T}\mu(k) \cdot \frac{T}{k} T=1nsum(Tn)2T2kTμ(k)kT

最后那个求和真的是一个狄利克雷卷积的形式,而且实际上就是

( μ ∗ I d ) ( T ) = ∑ k ∣ T μ ( k ) ⋅ T k (\mu*Id)(T)=\sum_{k|T}\mu(k) \cdot \frac{T}{k} (μId)(T)=kTμ(k)kT

众所周知(这里不再赘述)

ϕ = μ ∗ I d \phi=\mu*Id ϕ=μId

所以原式就变成了

∑ T = 1 n s u m ( ⌊ n T ⌋ ) 2 ⋅ T 2 ⋅ ϕ ( T ) \sum_{T=1}^{n}sum(\lfloor \frac{n}{T} \rfloor)^2 \cdot T^2 \cdot \phi(T) T=1nsum(Tn)2T2ϕ(T)

F ( T ) = T 2 ⋅ ϕ ( T ) F(T)=T^2 \cdot \phi(T) F(T)=T2ϕ(T),因为 F F F是积性函数,所以可以用杜教筛来算。对于这个式子整除分块,就可以在大概 O ( n 5 6 ) O(n^{\frac{5}{6}}) O(n65)(我也不知道这个复杂度怎么算啊不可能这么大的啊这样的复杂度过不了1e10啊大概杜教筛预处理加上可能跑得还挺快的吧所以还是改成 O ( O( O(能过 ) ) )好了)的时间做出来了。

杜教筛的话我们 另请高明

f ( n ) = n 2 ϕ ( n ) , g ( n ) = n 2 f(n)=n^2 \phi(n),g(n)=n^2 f(n)=n2ϕ(n),g(n)=n2

( f ∗ g ) ( n ) = n 3 (f*g)(n)=n^3 (fg)(n)=n3

然后手推二次方前缀和和三次方前缀和,完事。

注意

实际上只要学过一些套路推推式子还是蛮简单的

一定要注意取模 n n n很大但是不能一开始就模掉,所以每次拿来计算的时候一定要取模!!!

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e7+10;
unordered_map<LL, LL> S;
LL n, Sp[N];
LL mod, inv_2, inv_4, inv_6, ans;
int p[N], pn;
bool vis[N];

inline int fpow(LL x, int y)
{
    LL ret = 1;
    while (y){
        if (y&1) ret = ret * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return ret;
}

inline void init()
{
    inv_2 = fpow(2, mod-2);
    inv_4 = fpow(4, mod-2);
    inv_6 = fpow(6, mod-2);
    Sp[1] = 1;
    for (int i = 2; i < N; ++ i){
        if (!vis[i])
            p[++pn] = i, Sp[i] = 1LL * (i - 1) * i % mod * i % mod;
        for (int j = 1; j <= pn; ++ j){
            if (1LL*i*p[j] >= N) break;
            vis[i*p[j]] = 1;
            if (i%p[j] == 0){
                Sp[i*p[j]] = Sp[i] * p[j] % mod * p[j] % mod * p[j] % mod;
                break;
            }
            else
                Sp[i*p[j]] = Sp[i] * (p[j] - 1) % mod * p[j] % mod * p[j] % mod;
        }
    }
    for (int i = 1; i < N; ++ i)
        (Sp[i] += Sp[i-1]) %= mod;
}

LL calc_3(LL n){return n * n % mod * (n + 1) % mod * (n + 1) % mod * inv_4 % mod;}

LL calc_2(LL n){return n * (n + 1) % mod * (2 * n + 1) % mod * inv_6 % mod;}

LL calc_1(LL n){return n * (n + 1) % mod * inv_2 % mod;}

// f(n)=n^2*phi(n) g(n)=Id(n)^2 h(n) = Id(n)^3
inline int get_S(LL n)
{
    if (n < N) return Sp[n];
    if (S.find(n) != S.end()) return S[n];
    LL ret = calc_3(n % mod);
    for (LL i = 2, j, d; i <= n; i = j+1){
        d = n/i; j = n/d;
        (ret -= (calc_2(j % mod) - calc_2((i - 1) % mod)) * get_S(d) % mod) %= mod;
    }
    if (ret < 0) ret += mod;
    return S[n] = ret;
}

inline LL solve()
{
    LL ans = 0;
    for (LL i = 1, j, d; i <= n; i = j+1){
        d = n/i; j = n/d;
        (ans += calc_1(d % mod) * calc_1(d % mod) % mod * (get_S(j) - get_S(i-1)) % mod) %= mod;
    }
    return ans < 0 ? ans+mod : ans;
}

int main()
{
    scanf("%lld%lld", &mod, &n);
    init();
    printf("%lld\n", solve());
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值