zoukankan      html  css  js  c++  java
  • BZOJ 2820 莫比乌斯反演

    思路:

    $Sigma_{i=1}^nSigma_{j=1}^mgcd(i,j)==p(p是素数)$


    $Sigma_{p是素数}^{p<=n}Sigma_{i=1}^{lfloor frac{n}{p} floor}Sigma_{j=1}^{lfloor frac{m}{p} floor}gcd(i,j)==1$


    由$e=μ|1$可得$gcd(i,j)==1 等价于 Sigma_{d|gcd(i,j)} μ(d)$


    所以原式为


    $Sigma_{p是素数}^{p<=n}Sigma_{i=1}^{lfloor frac{n}{p} floor}Sigma_{j=1}^{lfloor frac{m}{p} floor}Sigma_{d|gcd(i,j)}μ(d)$


    $Sigma_{p是素数}^{p<=n}Sigma_{i=1}^{lfloor frac{n}{p} floor}Sigma_{j=1}^{lfloor frac{m}{p} floor}Sigma_{d|i且d|j}μ(d)$


    $Sigma_{p是素数}^{p<=n}Sigma_{d=1}^{frac{n}{p}}lfloor{frac{n}{pd}} floorlfloor{frac{m}{pd}} floor μ(d)$


    设$k=pd$


    $Sigma_{k=1}^{min(n,m)}lfloor{frac{n}{k}} floorlfloor{frac{m}{k}} floorSigma_{p|k}μ(frac{k}{p})$

    设$g(x)=Sigma_{p|k}μ(frac{k}{p})$


    可以预处理g(x)


    怎么求g(x)呢


    有两种方法


    1.暴力枚举


    枚举素数 p


    用$μ(p)$更新$μ(i*p)(i*p<=max(n,m))$


    这样素数有$n/logn$个


    枚举i的均摊复杂度是$O(logn)$的


    乘起来就是$O(n)$了


    2.
    线性筛

    对于素数p g(p)=1(显然)

    由于$μ(x)_{x的因子有平方项}=0$


    所以$prime[j]|i$的时候$g(i*prime[j])$的结果就是$μ(i)$了


    因为我们求的是$Sigma_{p|k}μ(frac{k}{p})$而且$μ(x)$是积性函数


    那我们不妨设$i*prime[j]=k$


    设$P$是包含$prime[j]$的所有素数 $p$是不包含$prime[j]$的所有素数


    $Sigma_{P|k}μ(frac{k}{P})=Sigma_{P|k}μ(frac{i*prime[j]}{P})$


    $=Sigma(μ(frac{i}{p})*μ(prime[j]))+μfrac{(i*prime[j])}{prime[j]}$


    $=μ(prime[j])*g[i]+μ(i)=-g[i]+μ(i)$

    处理完了g(x)


    原式就是这个样子的$Sigma_{k=1}^{min(n,m)}lfloor{frac{n}{k}} floorlfloor{frac{m}{k}} floor g(k)$


    对于g(k)搞个前缀和


    $lfloor{frac{n}{k}} floorlfloor{frac{m}{k}} floor$这个东西可以分块


    终于搞完了
    喜闻乐见
    吼吼

    枚举素数的

    //By SiriusRen
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int maxn=10000005;
    #define int long long
    int cases,n,m,mu[maxn],p[maxn],sum[maxn],f[maxn],tot;
    long long ans;bool vis[maxn];
    signed main(){
        mu[1]=1;
        for(int i=2;i<maxn;i++){
            if(!vis[i])p[++tot]=i,mu[i]=-1;
            for(int j=1;j<=tot&&i*p[j]<maxn;j++){
                mu[i*p[j]]=-mu[i],vis[i*p[j]]=1;
                if(!(i%p[j])){mu[i*p[j]]=0;break;}
            }
        }
        for(int i=1;i<=tot;i++)
            for(int j=1;j*p[i]<maxn;j++)f[j*p[i]]+=mu[j];
        for(int i=1;i<maxn;i++)f[i]+=f[i-1];
        scanf("%d",&cases);
        while(cases--){
            scanf("%d%d",&n,&m),ans=0;
            if(n>m)swap(n,m);
            for(int i=1,j;i<=n;i=j+1){
                j=min(n/(n/i),m/(m/i));
                ans+=(f[j]-f[i-1])*(n/i)*(m/i);
            }
            printf("%lld
    ",ans);
        }
    }

    这是线性筛的

    //By SiriusRen
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    const int N=10000005;
    int T,prime[N],vis[N],mu[N],tot,n,m;ll f[N],ans;
    int main(){
        mu[1]=1;
        for(int i=2;i<N;i++){
            if(!vis[i])prime[++tot]=i,mu[i]=-1,f[i]=1;
            for(int j=1;i*prime[j]<N&&j<=tot;j++){
                vis[i*prime[j]]=1,mu[i*prime[j]]=-mu[i],f[i*prime[j]]=-f[i]+mu[i]; 
                if(i%prime[j]==0){mu[i*prime[j]]=0;f[i*prime[j]]=mu[i];break;}
            }f[i]+=f[i-1];
        }
        scanf("%d",&T);
        while(T--){
            scanf("%d%d",&n,&m),ans=0;
            for(int l=1,r;l<=min(n,m);l=r+1){
                r=min(n/(n/l),m/(m/l));
                ans+=1ll*(f[r]-f[l-1])*(n/l)*(m/l);
            }printf("%lld
    ",ans);
        }
    }
  • 相关阅读:
    11.6八校联考T1,T2题解
    NOIP2014解方程
    luogu P2107 小Z的AK计划
    差分及树上差分学习笔记
    Noip2015提高组解题报告
    日常个人训练计划
    dij 费用流
    哈尔滨站总结
    SOSdp
    2018-2019 ACM-ICPC Southeastern European Regional Programming Contest (SEERC 2018)
  • 原文地址:https://www.cnblogs.com/SiriusRen/p/6680518.html
Copyright © 2011-2022 走看看