#莫比乌斯反演,杜教筛#洛谷 3768 简单的数学题

题目

∑ i = 1 n ∑ j = 1 n i j g c d ( i , j ) ( m o d p ) \sum_{i=1}^n\sum_{j=1}^nijgcd(i,j)\pmod p i=1nj=1nijgcd(i,j)(modp)


分析

一波推式子
= ∑ i = 1 n ∑ j = 1 n i j ∑ k ∣ i , k ∣ j φ ( k ) =\sum_{i=1}^n\sum_{j=1}^nij\sum_{k|i,k|j}\varphi(k) =i=1nj=1nijki,kjφ(k)
= ∑ k = 1 n φ ( k ) k 2 ∑ i = 1 ⌊ n k ⌋ ∑ j = 1 ⌊ n k ⌋ i j =\sum_{k=1}^n\varphi(k)k^2\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{k}\rfloor}ij =k=1nφ(k)k2i=1knj=1knij
= ∑ k = 1 n φ ( k ) k 2 ( ∑ i = 1 ⌊ n k ⌋ i ) 2 =\sum_{k=1}^n\varphi(k)k^2(\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}i)^2 =k=1nφ(k)k2(i=1kni)2
= ∑ k = 1 n φ ( k ) k 2 ∑ i = 1 ⌊ n k ⌋ i 3 =\sum_{k=1}^n\varphi(k)k^2\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}i^3 =k=1nφ(k)k2i=1kni3
把右边视为 g ( ⌊ n k ⌋ ) g(\lfloor\frac{n}{k}\rfloor) g(kn),左边视为 f ( k ) f(k) f(k)
那么其实这个式子可以变成 ∑ k = 1 n f ( k ) g ( ⌊ n k ⌋ ) \sum_{k=1}^nf(k)g(\lfloor\frac{n}{k}\rfloor) k=1nf(k)g(kn)
后面这个东西整除分块,前面套杜教筛,时间复杂度 O ( n 2 3 ) O(n^{\frac{2}{3}}) O(n32)
比如说我们要求 f f f,用 h = ( f ∗ g ) h=(f*g) h=(fg)去配对,所以要找到一个合适的 g g g去卷积,后面的 g g g是新的 g g g
那么 h ( x ) = ∑ i ∣ x f ( i ) ∗ g ( x / i ) h(x)=\sum_{i|x}f(i)*g(x/i) h(x)=ixf(i)g(x/i)
g ( x ) g(x) g(x)可以用 x 2 x^2 x2代替
那么 h ( x ) = ∑ i ∣ x φ ( i ) x 2 = x 3 h(x)=\sum_{i|x}\varphi(i)x^2=x^3 h(x)=ixφ(i)x2=x3
那就可以按照杜教筛的方式解决


代码

#include <cstdio>
#include <map>
#define rr register
using namespace std;
typedef long long ll; map<ll,ll>uk;
const int N=4700000; int v[N|1],cnt,prime[330001]; ll n,mod,inv,phi[N|1],ans;
inline ll mo(ll x,ll y){return x+y>=mod?x+y-mod:x+y;} 
inline ll g(ll n){n%=mod; return n*(n+1)%mod*(n<<1|1)%mod*inv%mod;}
inline ll sqr(ll n){return n*n%mod;}
inline ll cub(ll n){n%=mod; return sqr((n*(n+1)>>1)%mod);}
inline void init(int n){
    phi[1]=1;
    for (rr int i=2;i<=n;++i){
        if (!v[i]) phi[i]=(prime[++cnt]=v[i]=i)-1;
        for (rr int j=1;j<=cnt&&prime[j]*i<=n;++j){
            v[i*prime[j]]=prime[j];
            if (i%prime[j]) phi[i*prime[j]]=phi[i]*phi[prime[j]];
            else {phi[i*prime[j]]=phi[i]*prime[j]; break;}
        }
    }
    for (rr int i=2;i<=n;++i) phi[i]=mo(phi[i-1],phi[i]*sqr(i)%mod);
}
inline ll f(ll n){
    if (n<=N) return phi[n];
    if (uk.find(n)!=uk.end()) return uk[n];
    rr ll ans=cub(n);
    for (rr ll l=2,r;l<=n;l=r+1)
        r=n/(n/l),ans=mo(ans-f(n/l)*(mo(g(r)-g(l-1),mod))%mod,mod);
    return uk[n]=mo(ans,mod);
}
inline ll ksm(ll x,ll y){
    rr ll ans=1;
    for (;y;y>>=1,x=x*x%mod)
        if (y&1) ans=ans*x%mod;
    return ans;
}
signed main(){
    scanf("%lld%lld",&mod,&n);
    init(n<N?n:N); inv=ksm(6,mod-2);
    for (rr ll l=1,r;l<=n;l=r+1)
        r=n/(n/l),ans=mo(ans,cub(n/l)*(mo(f(r)-f(l-1),mod))%mod);
    return !printf("%lld",mo(ans,mod));
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值