LOJ6229 这是一道简单的数学题

筅森魡賤 提交于 2020-03-03 10:34:13

这是一道简单的数学题

\[ F(n)=\sum_{i=1}^n\sum_{j=1}^i\frac{\mathrm{lcm}(i,j)}{\mathrm{gcd}(i,j)} \]

其中,\(\mathrm{lcm}(a,b)\) 表示 \(a\)\(b\) 的最小公倍数,\(\mathrm{gcd}(a,b)\) 表示 \(a\)\(b\) 的最大公约数。

给定 \(n\) ,让你求: \(F(n) \bmod1000000007\)

对于所有数据,\(1 \le n \le 10^9\)

题解

\[ F(n)=\sum_{i=1}^n\sum_{j=1}^i \frac{ij}{\gcd(i,j)^2}\\ =\sum_{d=1}^n\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^i ij[\gcd(i,j)=1]\\ =\sum_{d=1}^n\sum_{x=1}^{\lfloor\frac{n}{d}\rfloor}\mu(x)x^2\sum_{i=1}^{\lfloor\frac{n}{dx}\rfloor}\sum_{j=1}^i ij\\ =\sum_{d=1}^n G(\lfloor\frac{n}{d}\rfloor) \]

\[ G(n)=\sum_{x=1}^n\mu(x)x^2\sum_{i=1}^{\lfloor\frac{n}{x}\rfloor}\sum_{j=1}^i ij\\ =\sum_{x=1}^n \mu(x)x^2 H(\lfloor\frac{n}{x}\rfloor) \]

\(\mu(x)x^2\) 的前缀和可以用杜教筛计算。

\[ H(n)=\sum_{i=1}^n\sum_{j=1}^i ij\\ =\sum_{i=1}^n i\frac{(i+1)i}{2}\\ =\frac{1}{2}((\frac{n(n+1)}{2})^2+\frac{1}{6}n(n+1)(2n+1)) \]

这样做有两层数论分块,而且第二层数论分块还套了一个杜教筛,跑的很慢。

CO int N=1e7+10;
int pri[N],tot,val[N];
unordered_map<int,int> vs;

int H(int n){
    int ans=fpow(mul(n,mul(n+1,i2)),2);
    ans=add(ans,mul(n,mul(n+1,mul(2*n+1,i6))));
    ans=mul(ans,i2);
    return ans;
}
int S(int n){
    if(n<N) return val[n];
    if(vs.count(n)) return vs[n];
    int ans=1;
    for(int l=2,r;l<=n;l=r+1){
        r=n/(n/l);
        int c=mul(r,mul(r+1,mul(2*r+1,i6)));
        c=add(c,mod-mul(l-1,mul(l,mul(2*l-1,i6))));
        ans=add(ans,mod-mul(c,S(n/l)));
    }
    return vs[n]=ans;
}
int G(int n){
    int ans=0;
    for(int l=1,r;l<=n;l=r+1){
        r=n/(n/l);
        int c=add(S(r),mod-S(l-1));
        ans=add(ans,mul(c,H(n/l)));
    }
    return ans;
}
int F(int n){
    int ans=0;
    for(int l=1,r;l<=n;l=r+1){
        r=n/(n/l);
        ans=add(ans,mul(r-l+1,G(n/l)));
    }
    return ans;
}

int main(){
    val[0]=0,val[1]=1;
    for(int i=2;i<N;++i){
        if(!pri[i]){
            pri[++tot]=i;
            val[i]=mod-mul(i,i);
        }
        for(int j=1;j<=tot and i*pri[j]<N;++j){
            pri[i*pri[j]]=1;
            if(i%pri[j]==0){
                val[i*pri[j]]=0;
                break;
            }
            val[i*pri[j]]=mul(val[i],val[pri[j]]);
        }
    }
    for(int i=1;i<N;++i) val[i]=add(val[i],val[i-1]);
    printf("%d\n",F(read<int>()));
    return 0;
}

可以观察到一个事实:莫比乌斯反演的辅助函数是 \(\varphi\) 的计算方式是比辅助函数是 \(\mu\) 的计算方式快的。

\[ F(n)=\sum_{d=1}^n \sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}i\sum_{j=1}^ij[\gcd(i,j)=1]\\ =\sum_{d=1}^n \sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}i\frac{[i=1]+i\varphi(i)}{2}\\ =\frac{n+\sum_{i=1}^n\varphi(i)i^2\lfloor\frac{n}{i}\rfloor}{2} \]

这样只有一个数论分块套杜教筛,用时约为上一种做法的五分之一。

复杂度分析

注意整除分块的写法:

for(int l=1,r;l<=n;l=r+1){
    r=n/(n/l);
    int c=add(S(r),mod-S(l-1));
    ans=add(ans,mul(c,n/l));
}

注意到r=n/(n/l),所以r仍然是 \(\lfloor\frac{n}{x}\rfloor\) 的形式。那么S的结果也就能用数组存储。

分析时间复杂度时可以认为S里面根号个值是预处理出来的。所以时间复杂度是 \(O(n^{\frac{2}{3}}+n^{\frac{1}{2}})\)

我懒得改上面用unordered_map的代码了。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!