zoukankan      html  css  js  c++  java
  • [2020HDU多校第九场][HDU 6868][B. Absolute Math]

    又被学弟们爆锤了TAT感觉可以原地退役了_(:з」∠)_

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6868

    题目大意:设(f(n)=sum_{d|n} |mu(d)|),求(sum_{i=1}^{m} f(ni))

    题解:分析(f(n))的性质,设(n=prod_{i=1}^{k} p_i^{q_i}),(omega = prod_{i=1}^{k} p_i ),显然当且仅当(d|omega)时存在贡献,而这样的(d)一共有(2^k)个。故若我们设(k(n))为(n)的不同质因子个数,则(f(n)=2^{k(n)}),是一个积性函数

       由于(k(n)=k(omega)),所以有(f(n)=f(omega)),进一步地我们可以得出,(sum_{i=1}^{m} f(ni)=sum_{i=1}^{m} f(omega i))。令(S(n,m)=sum_{i=1}^{m} f(ni)),则有(S(n,m)=S(omega,m))

       注意到(omega)是不同质数的乘积,因此(f(omega i)=f(i)cdot f(frac{omega}{gcd(i,omega)})),就有$$S(n,m)=S(omega,m)=sum_{i=1}^{m} f(omega i)=sum_{i=1}^{m} f(i)cdot f(frac{omega}{gcd(i,omega)})$$

       枚举(d=gcd(i,omega)),得到$$S(omega,m)=sum_{d|omega}f(frac{omega}{d})sum_{i=1}^{lfloor frac{m}{d} floor}f(id)[gcd(i,frac{omega}{d})=1]$$

       由(sum_{d|n}mu(d)=[n==1])$$S(omega,m)=sum_{d|omega}f(frac{omega}{d})sum_{i=1}^{lfloor frac{m}{d} floor}f(id)sum_{e|gcd(i,frac{omega}{d})}mu(e)$$

       交换求和次序,则答案为$$sum_{d|omega}f(frac{omega}{d})sum_{e|frac{omega}{d}}mu(e)sum_{i=1}^{lfloor frac{m}{de} floor}f(ide)$$

       设(T=dcdot e),则有(T|omega),再次交换求和次序,得出答案为$$sum_{T|omega}sum_{i=1}^{lfloor frac{m}{T} floor}f(iT)sum_{d|T}mu(d)f(frac{omega}{frac{T}{d}})=sum_{T|omega}S(T,lfloor frac{m}{T} floor)sum_{d|T}mu(d)f(dcdot frac{omega}{T})$$

       再次注意到(omega)是不同质数的乘积,因此有对任意(T|omega),(gcd(T,frac{omega}{T})=1),而由于(d|T),故(f(dcdot frac{omega}{T})=f(d)f(frac{omega}{T})),因此有$$S(omega,m)=sum_{T|omega}S(T,lfloor frac{m}{T} floor)sum_{d|T}mu(d)f(d)f(frac{omega}{T})=sum_{T|omega}f(frac{omega}{T})S(T,lfloor frac{m}{T} floor)sum_{d|T}mu(d)f(d)$$

       其中(f)的值可以(O(n))线性筛预处理,(S)可以递归求解,现在问题就在于求(sum_{d|T}mu(d)f(d))的值

       注意到这边(T)也是若干个不同质数的乘积,而(f(d)=2^{k(d)}, mu(d)=(-1)^{k(d)}),考虑对所有相同的(k)进行求和,则有(sum_{d|T}mu(d)f(d)=sum_{i=0}^{k(T)}C_{k(T)}^{i}2^icdot(-1)^i),发现这是一个类似于二项式展开的形式,计算得出$$sum_{d|T}mu(d)f(d)=sum_{i=0}^{k(T)}C_{k(T)}^{i}2^icdot(-1)^{k(T)-i}cdot(-1)^{-k(T)+2i}=(-1)^{k(T)}cdot (2+(-1))^{k(T)}=(-1)^{k(T)}cdot 1=mu(T)$$

       于是我们就得出了最终的式子$$S(n,m)=S(omega,m)=sum_{T|omega}mu(T)f(frac{omega}{T})S(T,lfloor frac{m}{T} floor)$$

       得到这个式子后直接递归求解即可,最坏情况下(n)是等于最小的八个质数的乘积(9699690),这种情况下在第一层最多也只会遍历到(256)个不同的(S(n,m))。赛中直接交跑了不到三秒就过了,赛后再交发现会TLE,加了些常数优化卡过去了_(:з」∠)_(赛中赛后运行时间差了整整一倍可还行)

    赛中过的代码

    #include<bits/stdc++.h>
    using namespace std;
    #define N 10000001
    #define LL long long
    #define MOD 1000000007
    int T,n,f[N],sf[N],mu[N],v[N],p[N],cnt;
    void pretype()
    {
        int mx=0;
        v[1]=f[1]=mu[1]=1;
        for(int i=2;i<N;i++){
            if(!v[i]){p[++cnt]=i,mu[i]=-1,f[i]=2,v[i]=i;}
            for(int j=1;j<=cnt && 1ll*i*p[j]<N;j++){
                v[i*p[j]]=v[i]*p[j];
                if(i%p[j]==0){f[i*p[j]]=f[i],v[i*p[j]]=v[i];break;}
                mu[i*p[j]]=-mu[i];
                f[i*p[j]]=2*f[i];
            }
        }
        for(int i=1;i<N;i++)sf[i]=(sf[i-1]+f[i])%MOD;
    }
    int S(int n,int m)
    {
        if(m==0)return 0;
        if(m==1)return f[n];
        if(n==1)return sf[m];
        int res=0;
        for(int d=1;d*d<=n;d++)if(n%d==0){
            res=(res+MOD+1ll*f[n/d]*S(d,m/d)%MOD*mu[d])%MOD;
            res=(res+MOD+1ll*f[d]*S(n/d,m/(n/d))%MOD*mu[n/d])%MOD;
        }
        return res;
    }
    int S2(int n,int m)
    {
        int res=0;
        for(int i=1;i<=m;i++)
            res=(res+f[i*n])%MOD;
        return res;
    }
    int main()
    {
        int T,n,m;
        pretype();
        scanf("%d",&T);
        while(T--){
            scanf("%d%d",&n,&m);
            printf("%d
    ",S(v[n],m));
            //cout<<S2(v[n],m)<<" "<<S2(n,m)<<endl;
        }
    }
    View Code

    卡常版(4914ms)

    #include<bits/stdc++.h>
    using namespace std;
    #define N 10000001
    #define MOD 1000000007
    int T,n,f[N],sf[N],mu[N],v[N],p[N],cnt;
    void pretype()
    {
        v[1]=f[1]=mu[1]=1;
        for(int i=2;i<N;i++){
            if(!v[i]){p[++cnt]=i,mu[i]=-1,f[i]=2,v[i]=i;}
            for(int j=1;j<=cnt && 1ll*i*p[j]<N;j++){
                v[i*p[j]]=v[i]*p[j];
                if(i%p[j]==0){f[i*p[j]]=f[i],v[i*p[j]]=v[i];break;}
                mu[i*p[j]]=-mu[i];
                f[i*p[j]]=2*f[i];
            }
        }
        for(int i=1;i<N;i++)sf[i]=(sf[i-1]+f[i])%MOD;
    }
    int S(int n,int m)
    {
        if(m==0)return 0;
        if(m==1)return f[n];
        if(n==1)return sf[m];
        int res=0;
        if(m<100 && n*m<N){
            for(int i=1;i<=m;i++)
                res=(res+f[i*n])%MOD;
            return res;
        }
        for(int d=1;d*d<=n;d++)if(n%d==0){
            res=(res+MOD+1ll*f[n/d]*S(d,m/d)%MOD*mu[d])%MOD;
            res=(res+MOD+1ll*f[d]*S(n/d,m/(n/d))%MOD*mu[n/d])%MOD;
        }
        return res;
    }
    int main()
    {
        int T,n,m;
        pretype();
        scanf("%d",&T);
        while(T--){
            scanf("%d%d",&n,&m);
            printf("%d
    ",S(v[n],m));
        }
    }
    View Code

    PS:本篇博客做法思路与[BZOJ 3512]的解法十分相似,阅读相关题解有助于进一步理解这种做法

    时间复杂度分析:

       咕咕咕.jpg,反正(O()能过())XD

  • 相关阅读:
    ArrayList用法
    MessageBox
    将文本文件导入Sql数据库
    在桌面和菜单中添加快捷方式
    泡沫排序
    Making use of localized variables in javascript.
    Remove double empty lines in Visual Studio 2012
    Using Operations Manager Connectors
    Clear SharePoint Designer cache
    Programmatically set navigation settings in SharePoint 2013
  • 原文地址:https://www.cnblogs.com/DeaphetS/p/13525554.html
Copyright © 2011-2022 走看看