• [洛谷P1390]公约数的和·莫比乌斯反演


    公约数的和

    传送门


    放在这么前面的位置当然是给自己看的!!!!!


    这一步原来是这么推过来的!如果下次再忘了怎么推可以这么搞出来或者直接记结论


    分析

    这道题很显然答案为

    [Ans=sum_{i=1}^nsum_{j=i+1}^n (i,j) ]

    //其中((i,j))意味(gcd(i,j))
    这样做起来很烦,看起来是(O(N^2))的辣鸡复杂度,我们考虑这个问题的弱化版
    求$$sum_{i=1}nsum_{j=1}n(i,j)$$
    然后通过一些优美的容斥就可以算出原答案

    现在我们设$$f(d)=sum_{i=1}nsum_{j=1}n[(i,j)=d]$$
    这个式子表示,在(i=1..n,j=1..n,gcd(i,j)=d)的个数,其中([])内成立,返回值为(1),否则为(0)
    我们令

    [F(n)=sum_{n|d}f(d)=lfloorfrac N n floor^2 ]

    则有

    [f(n)=sum_{n|d}mu(frac d n)F(d)$$$$=sum_{n|d}mu(frac d n)lfloorfrac N d floor^2 ]

    考虑(Ans)

    [Ans=sum_{i=1}^nsum_{j=1}^n(i,j) ]

    [=sum_{d=1}^n dsum_{i=1}^nsum_{j=1}^n[(i,j)=d] ]

    [=sum_{d=1}^n d;f(d) ]

    考虑把(f(d))的式子带入,这时我们不枚举(d)的倍数具体是多少,而是枚举倍数(不枚举(d|n)(n),而是枚举(frac n d),比如说我们用(k)表示,就有

    [=sum_{d=1}^N d sum_{k=1}^Nmu(k)lfloorfrac{N}{dk} floor^2 ]

    这个(dk)感觉不是很舒服,我们令(t=dk,将枚举d改为枚举dk,则有)

    [=sum_{t=1}^Nsum_{k|t} kmu(frac{t}{k})lfloorfrac{N}{t} floor^2 ]

    观察$$sum_{k|t} kmu(frac{t}{k})$$
    我们发现这是在前文提及的狄利克雷卷积

    [mu imes d=phi ]

    (忘了的话戳这里)
    本篇·莫比乌斯反演
    那么原式就优美的化简为

    [sum_{t=1}^Nphi(t)lfloorfrac{N}{t} floor^2 ]

    这样一个式子已经可以(O(N))地解决了,更优美地也可以进行整除分块,做到计算(sqrt{n})

    关于最前面的容斥,只需要减去(gcd(i,i)=i)(gcd(i,j)=gcd(j,i))的情况就可以
    对于(gcd(i,i)=i)的情况,考虑在(sum_{i=1}^nsum_{j=1}^n(i,j))中,对于每个(i),有且仅有(1)(j=i)对应,此时的贡献为(i),所以总贡献为
    (sum_{i=1}^N i=N(N+1)/2)
    (gcd(i,j)=gcd(j,i))的情况,去掉情况(1)后显然这两个对半分,只要(/2)即可

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int maxn=2000010;
    LL sum[maxn];
    int vis[maxn],phi[maxn],pri[maxn];
    int cnt=0,n;
    inline void getphi(int n){
        memset(vis,0,sizeof(vis));phi[1]=vis[1]=1;
        for (int i=2;i<=n;i++){
            if (!vis[i]){pri[++cnt]=i;phi[i]=i-1;}
            for (int j=1;j<=cnt&&(LL)i*pri[j]<=n;j++){
                vis[i*pri[j]]=1;
                if (i%pri[j]==0){phi[i*pri[j]]=phi[i]*pri[j];break;}
                else phi[i*pri[j]]=phi[i]*(pri[j]-1);
            }
        }
        for (int i=1;i<=n;i++) sum[i]=sum[i-1]+phi[i];
    }
    int main(){
        scanf("%d",&n);
        getphi(n);
        LL ans=0;
        for (int l=1,r;l<=n;l=r+1){
            r=n/(n/l);
            ans+=(LL)(sum[r]-sum[l-1])*(n/l)*(n/l);
        }
        printf("%lld",(ans-(LL)n*(n+1)/2)/2);
        return 0;
    }
    
    
  • 相关阅读:
    PSNR计算
    Latex中的(左边有大括号的)方程组解决方案汇总
    CS (Compressive sensing, 压缩传感)
    OpenCV 2.3.0 编译错误之 file INSTALL cannot find opencv_ffmpeg230d.dll(无法找到opencv_ffmpeg230d.dll)
    Visual Studio 2008 编译程序时的 mt.exe 返回错误
    fontDialog,colorDialog,saveDialog改变字体大小,颜色,以后保存图片文件实例
    Lambda入门示例实例
    C#接口入门基础知识复习
    C#,visual studio 2010中实现最简单DragDrop实例
    抽象类实现条件参数必须和抽象类中的一样
  • 原文地址:https://www.cnblogs.com/ugly-CYW-lyr-ddd/p/9196568.html
Copyright © 2020-2023  润新知