洛谷P3768 简单的数学题(莫比乌斯反演+杜教筛+狄利克雷卷积)

题目链接
我错了,杜教筛不是只背板子就够的qwq
跟着神仙yyb推了一遍式子,感觉这题还是很神仙
题意是求
i = 1 n j = 1 n i j g c d ( i , j ) \sum_{i=1}^{n}\sum_{j=1}^{n}ijgcd(i,j)
显然先把gcd枚举一下,假设gcd(i,j)==k
原式就为
k = 1 n k i = 1 n j = 1 n i j [ g c d ( i , j ) = = k ] \sum_{k=1}^{n}k\sum_{i=1}^{n}\sum_{j=1}^{n}ij[gcd(i,j)==k]
后面这个式子根据套路可以往外提一下
k = 1 n k 3 i = 1 n / k j = 1 n / k i j [ g c d ( i , j ) = = 1 ] \sum_{k=1}^{n}k^3\sum_{i=1}^{n/k}\sum_{j=1}^{n/k}ij[gcd(i,j)==1]
这样子看着一脸可莫比乌斯反演的样子
f ( x ) = i = 1 x j = 1 x i j [ g c d ( i , j ) = = 1 ] f(x)=\sum_{i=1}^{x}\sum_{j=1}^{x}ij[gcd(i,j)==1]
根据某引理
d x μ ( d ) = [ x = 1 ] \sum_{d|x}\mu(d)=[x=1]
f ( x ) = i = 1 x j = 1 x d g c d ( i , j ) μ ( d ) f(x)=\sum_{i=1}^{x}\sum_{j=1}^{x}\sum_{d|gcd(i,j)}\mu(d)
换过来枚举d
f ( x ) = d = 1 x μ ( d ) d i d j i j f(x)=\sum_{d=1}^{x}\mu(d)\sum_{d|i}\sum_{d|j}ij
后面那玩意可以O(1)算的
f ( x ) = d = 1 x μ ( d ) d 2 ( 1 + 2 + 3 + . . . + [ x d ] ) 2 f(x)=\sum_{d=1}^{x}\mu(d)d^2(1+2+3+...+[\frac{x}{d}])^2
反演完了,我们把它代回去
k = 1 n k 3 f ( [ n k ] ) \sum_{k=1}^{n}k^3f([\frac{n}{k}])
k = 1 n k 3 d = 1 n / k μ ( d ) d 2 ( 1 + 2 + 3 + . . . + [ n k d ] ) 2 \sum_{k=1}^{n}k^3\sum_{d=1}^{n/k}\mu(d)d^2(1+2+3+...+[\frac{n}{kd}])^2
s u m ( x ) = 1 + 2 + 3 + . . . + x , g = k d sum(x)=1+2+3+...+x,g=kd 枚举g,再随便枚举个k
g = 1 n s u m ( g ) 2 k g k 3 ( g k ) 2 μ ( g k ) \sum_{g=1}^{n}sum(g)^2\sum_{k|g}k^3(\frac{g}{k})^2\mu(\frac{g}{k})
有些项可以消掉
g = 1 n s u m ( g ) 2 k g g 2 k μ ( g k ) \sum_{g=1}^{n}sum(g)^2\sum_{k|g}g^2k\mu(\frac{g}{k})
显然 g 2 g^2 可以提出来
g = 1 n s u m ( n g ) 2 g 2 k g k μ ( g k ) \sum_{g=1}^{n}sum(\frac{n}{g})^2g^2\sum_{k|g}k\mu(\frac{g}{k})
显然前面可以整除分块
主要需要快速求出后面的
g 2 k g k μ ( g k ) g^2\sum_{k|g}k\mu(\frac{g}{k})
这时候狄利克雷卷积就有用了
常见的几个狄利克雷卷积
d = 1 1 d=1*1
σ = 1 i d \sigma=1*id
e = 1 μ e=1*\mu
ϕ = μ i d \phi=\mu*id
i d = ϕ 1 id=\phi*1
显然这里我们需要用的是 ϕ = μ i d \phi=\mu*id
卷完以后我们可以得到
f ( g ) = g 2 ϕ ( g ) f(g)=g^2\phi(g)
这时候需要计算上面函数的前缀和 s ( n ) s(n) ,那么就是杜教筛的套路
g ( 1 ) s ( n ) = i = 1 n ( g f ) ( i ) i = 2 n g ( i ) s ( n i ) g(1)s(n)=\sum_{i=1}^{n}(g*f)(i)-\sum_{i=2}^{n}g(i)s(\frac{n}{i})
看看要卷的东西
( g f ) ( i ) = d i g ( d ) f ( i d ) = d i g ( d ) ( i d ) 2 ϕ ( i d ) (g*f)(i)=\sum_{d|i}g(d)f(\frac{i}{d}) =\sum_{d|i}g(d)(\frac{i}{d})^2\phi(\frac{i}{d})
显然令 g ( x ) = x 2 g(x)=x^2 就可以把 ( i d ) 2 (\frac{i}{d})^2 消掉
i 2 d i ϕ ( i d ) i^2\sum_{d|i}\phi(\frac{i}{d})
1 ϕ ( i ) = i d 1*\phi(i)=id
i 2 d i ϕ ( i d ) = i 3 i^2\sum_{d|i}\phi(\frac{i}{d})=i^3
s ( n ) = i = 1 n i 3 i = 2 n i 2 s ( n i ) s(n)=\sum_{i=1}^{n}i^3-\sum_{i=2}^{n}i^2s(\frac{n}{i})
这个前缀和用杜教筛处理之后,总复杂度是 O ( n 2 3 ) O(n^{\frac{2}{3}})

代码如下:

#include<bits/stdc++.h>
#define N 8000000
using namespace std;

long long phi[N+10];
int p[N+10];
bool vis[N+10];
long long n,cnt,mod,inv2,inv6;
map<long long,long long> m;

long long kasumi(long long a,long long b)
{
    long long ans=1;
    while(b)
    {
        if(b&1) ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans;
}

void init()
{
    phi[1]=1;
    for(int i=2;i<=N;i++)
    {
        if(!vis[i])
        {
            p[++cnt]=i;
            phi[i]=i-1;
        }
        for(int j=1;j<=cnt;j++)
        {
            if(i*p[j]>N) break;
            vis[i*p[j]]=1;
            if(!(i%p[j])) {phi[i*p[j]]=phi[i]*p[j];break;}
            else phi[i*p[j]]=phi[i]*phi[p[j]];
        }
    }
    for(int i=1;i<=N;i++) phi[i]=(phi[i]*i%mod*i%mod+phi[i-1])%mod;
}

inline long long sum2(long long x)
{
    x%=mod;
    return x*(x+1)%mod*(x+x+1)%mod*inv6%mod;
}

inline long long sum3(long long x)
{
    x%=mod;
    return x*(x+1)%mod*inv2%mod;
}

long long solve(long long x)
{
    if(x<=N) return phi[x];
    if(m.count(x)) return m[x];
    long long res=sum3(x);
    res=res*res%mod;
    for(long long l=2,r;l<=x;l=r+1)
    {
        r=(x/(x/l));
        long long tmp=(sum2(r)-sum2(l-1));
        res-=tmp*solve(x/l);
        res%=mod;
    }
    return m[x]=(res+mod)%mod;
}

int main()
{
    scanf("%lld%lld",&mod,&n);
    inv2=kasumi(2,mod-2);
    inv6=kasumi(6,mod-2);
    init();
    long long ans=0;
    for(long long l=1,r;l<=n;l=r+1)
    {
        r=(n/(n/l));
        long long tmp=sum3(n/l);
        tmp=tmp*tmp%mod;
        long long res=(solve(r)-solve(l-1))%mod;
        ans+=res*tmp%mod;
        ans%=mod;
    }
    printf("%lld\n",(ans+mod)%mod);
}

猜你喜欢

转载自blog.csdn.net/qq_21829533/article/details/88090915
今日推荐