zoukankan      html  css  js  c++  java
  • 【洛谷3768】简单的数学题(莫比乌斯反演+杜教筛)

    点此看题面

    大致题意:(sum_{i=1}^nsum_{j=1}^nijgcd(i,j)\%p)

    前置技能

    关于这道题目,我们首先需要了解以下知识:

    知道这些,你就可以对这题的做法有一定的理解了。

    推式子

    首先,按照常见的套路,我们可以枚举(gcd(i,j)=d),得到这样一个式子:

    [sum_{d=1}^nsum_{i=1}^nsum_{j=1}^nijd[gcd(i,j)==d] ]

    然后,我们可以进行一个比较简单的转化,将中括号里面的(d)提出:

    [sum_{d=1}^nsum_{i=1}^{lfloorfrac nd floor}sum_{j=1}^{lfloorfrac nd floor}ijd^3[gcd(i,j)==1] ]

    不难发现(d^3)(i,j)无关,于是我们可以将其提前:

    [sum_{d=1}^nd^3sum_{i=1}^{lfloorfrac nd floor}sum_{j=1}^{lfloorfrac nd floor}ij[gcd(i,j)==1] ]

    然后我们可以枚举(gcd(i,j)=p),并对原式做一遍莫比乌斯反演,可以得到这样一个式子:

    [sum_{d=1}^nd^3sum_{p=1}^{lfloorfrac nd floor}mu(p)sum_{i=1}^{lfloorfrac n{d·p} floor}sum_{j=1}^{lfloorfrac n{d·p} floor}(i·p)(j·p) ]

    然后将(p)提出,就变成了这样:

    [sum_{d=1}^nd^3sum_{p=1}^{lfloorfrac nd floor}mu(p)p^2(sum_{i=1}^{lfloorfrac n{d·p} floor}i)(sum_{j=1}^{lfloorfrac n{d·p} floor}j) ]

    对于式子中的((sum_{i=1}^{lfloorfrac n{d·p} floor}i)(sum_{j=1}^{lfloorfrac n{d·p} floor}j)),可以化简得((frac{{lfloorfrac n{d·p} floor}·({lfloorfrac n{d·p} floor}+1)}2)^2)

    那么原式就变成了这个样子:

    [sum_{d=1}^nd^3sum_{p=1}^{lfloorfrac nd floor}mu(p)p^2(frac{{lfloorfrac n{d·p} floor}·({lfloorfrac n{d·p} floor}+1)}2)^2 ]

    如果设(s=d·p),则原式就变成了这个样子:

    [sum_{s=1}^nsum_{d|s}d^3mu(frac sd)frac{s^2}{d^2}(frac{{lfloorfrac n{d·p} floor}·({lfloorfrac n{d·p} floor}+1)}2)^2 ]

    注意到式子中的(d^2)似乎可以约去,于是我们可以得到下面这个式子:

    [sum_{s=1}^ns^2(frac{{lfloorfrac n{d·p} floor}·({lfloorfrac n{d·p} floor}+1)}2)^2sum_{d|s}dmu(frac sd) ]

    对于后面的一个式子(sum_{d|s}dmu(frac sd)),用狄利克雷卷积的形式来表示就是这个样子:

    [(mu*id)(s) ]

    而众所周知,(id=I*phi),所以我们可以考虑将其代入,得到:

    [(mu*I*phi)(s) ]

    (mu*I=e)刚好约掉,所以这个式子的结果就是:

    [phi(s) ]

    再代回原式就化简出来一个比较简单的式子了:

    [sum_{s=1}^n(s^2phi(s))(frac{{lfloorfrac n{d·p} floor}·({lfloorfrac n{d·p} floor}+1)}2)^2 ]

    于是,我们可以考虑杜教筛筛出(s^2phi(s)),然后除法分块求出前面一部分的值;而后面的((frac{{lfloorfrac n{d·p} floor}·({lfloorfrac n{d·p} floor}+1)}2)^2)一项是可以(O(1))计算的。

    于是这道题就这样解决了。

    代码

    #include<bits/stdc++.h>
    #define LL long long
    #define sum_sqr(x) ((((x)%MOD)*(((x)+1)%MOD))%MOD*((((x)<<1)+1)%MOD)%MOD*InvSix%MOD)//求1^2+2^2+...+x^2的结果
    #define sum_cube(x) ((((x)%MOD)*(((x)+1)%MOD)%MOD*InvTwo%MOD)*(((x)%MOD)*(((x)+1)%MOD)%MOD*InvTwo%MOD)%MOD)//求1^3+2^3+...+x^3的结果
    #define Inc(x,y) ((x+=(y))>=MOD&&(x-=MOD))
    #define Dec(x,y) ((x-=(y))<0&&(x+=MOD))
    using namespace std;
    LL n,MOD,InvTwo,InvSix;//分别用InvTwo和InvSix存储模MOD意义下2和6的逆元
    inline LL Sum(LL x,LL y) {return Inc(x,y),x;}
    inline LL Sub(LL x,LL y) {return Dec(x,y),x;}
    class Class_DuSieve//杜教筛
    {
        private:
            #define Size 5000000
            int Prime_cnt,Prime[Size+5],phi[Size+5];bool IsNotPrime[Size+5];LL sum_phi[Size+5];
            map<LL,LL> MemoryPhi;
        public:
            inline void Init()
            {
                register LL i,j;
                for(phi[1]=1,i=2;i<=Size;++i)
                {
                    if(!IsNotPrime[i]) phi[Prime[++Prime_cnt]=i]=i-1;
                    for(j=1;j<=Prime_cnt&&i*Prime[j]<=Size;++j)
                        if(IsNotPrime[i*Prime[j]]=true,i%Prime[j]) phi[i*Prime[j]]=phi[i]*(Prime[j]-1);else {phi[i*Prime[j]]=phi[i]*Prime[j];break;}
                }
                for(i=1;i<=Size;++i) sum_phi[i]=Sum(sum_phi[i-1],i*i%MOD*phi[i]%MOD);
            }
            inline LL GetPhi(LL x)
            {
                if(x<=Size) return sum_phi[x];
                if(MemoryPhi[x]) return MemoryPhi[x];
                register LL l,r,res=sum_cube(x);
                for(l=2;l<=x;l=r+1) r=x/(x/l),Dec(res,Sub(sum_sqr(r),sum_sqr(l-1))*GetPhi(x/l)%MOD);//递归调用
                return MemoryPhi[x]=res;
            }
    }DuSieve;
    inline LL quick_pow(LL x,LL y,register LL res=1)//快速幂求逆元
    {
        for(;y;(x*=x)%=MOD,y>>=1) if(y&1) (res*=x)%=MOD;
        return res;
    }
    int main()
    {
        register LL l,r,ans=0;
        scanf("%lld%lld",&MOD,&n),DuSieve.Init(),InvTwo=quick_pow(2,MOD-2),InvSix=quick_pow(6,MOD-2);//预处理
        for(l=1;l<=n;l=r+1) r=n/(n/l),Inc(ans,Sub(DuSieve.GetPhi(r),DuSieve.GetPhi(l-1))*sum_cube(n/l)%MOD);//除法分块求答案
        return printf("%lld",ans),0;
    }
    
  • 相关阅读:
    nowcoderD Xieldy And His Password
    Codeforces681D Gifts by the List
    nowcoder80D applese的生日
    Codeforces961E Tufurama
    Codeforces957 Mahmoud and Ehab and yet another xor task
    nowcoder82E 无向图中的最短距离
    nowcoder82B 区间的连续段
    Codeforces903E Swapping Characters
    Codeforces614C Peter and Snow Blower
    Codeforces614D Skills
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu3768.html
Copyright © 2011-2022 走看看