zoukankan      html  css  js  c++  java
  • bzoj3512: DZY Loves Math IV

    开始莫反强行拿掉欧拉函数搞出了一个这样的柿子。。。sigema(1~n)c sigema(1~n*m/c)d u(d)* (1+n/c)*(n/c)/2 * (1+m/(d/c))*(m/(d/c))/2

    自以为很对结果后来发现居然没办法把u给处理出来。。。囧

    结果发现是个杜教筛裸题的哥哥题

    然后这个n这么小肯定就是给你枚举的,令S(n,m)=sigema(1~m)i phi(n*i),答案就是sigema(1~n)i S(i,m)

    考虑S(n,m)怎么算

    对于欧拉函数的值,根据柿子可以理解为每个质因子被加入ci次,第一次贡献为pi-1,之后就是p

    把n给拆了,每个质因子只保留1个记作w,原式=(n/w)*sigema(1~m)i phi(w*i)

    根据欧拉函数的性质可得sigema(1~m)i phi(w*i)=sigema(1~m) phi(w/gcd(w,i))*phi(i)*gcd(w,i)

    把gcd拿掉变成sigema(1~m) phi(i)*phi(w/gcd(w,i))*sigema(d|gcd(w,i))phi(d)

    d和w/gcd(w,i)明显互质,压进去就变成 sigema(1~m) phi(i)*sigema(d|gcd(w,i))phi(w/d)

    改变枚举顺序,再把整除去掉变成sigema(d|w)phi(w/d)*sigema(1~m/d)i phi(i*d)=sigema(d|w)phi(w/d)*S(d,m/d)

    那么n=1直接杜教筛,m<=1特判一下,S(n,m)=(n/w)*sigema(d|w)phi(w/d)*S(d,m/d),记忆化搜索就过了

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<map>
    using namespace std;
    typedef long long LL;
    const int _=1e2;
    const int maxn=1e6+_;
    const LL mod=1e9+7;
    
    int pr,prime[maxn];bool v[maxn];
    int phi[maxn];LL sphi[maxn];
    void getprime()
    {
        phi[1]=sphi[1]=1;
        for(int i=2;i<maxn;i++)
        {
            if(v[i]==false)
                prime[++pr]=i,phi[i]=i-1;
            for(int j=1;j<=pr&&i*prime[j]<maxn;j++)
            {
                int k=i*prime[j];
                v[k]=true;
                if(i%prime[j]==0)
                    {phi[k]=phi[i]*prime[j];break;}
                else phi[k]=phi[i]*(prime[j]-1);
            }
            sphi[i]=sphi[i-1]+phi[i];if(sphi[i]>=mod)sphi[i]-=mod;
        }
    }
    map<int,int>PHI;
    int getphi(int n)
    {
        if(n<maxn)return phi[n];
        if(PHI.find(n)!=PHI.end())return PHI[n];
        int ret=n;
        for(int i=2;i*i<=n;i++)
            if(n%i==0)
            {
                ret=ret/i*(i-1);
                while(n%i==0)n/=i;
            }
        if(n!=1)ret=ret/n*(n-1);
        PHI[n]=ret;
        return ret;
    }
    map<int,LL>SPHI;
    LL getsphi(int n)
    {
        if(n<maxn)return sphi[n];
        if(SPHI.find(n)!=SPHI.end())return SPHI[n];
        LL ret=(LL)(1+n)*n/2%mod; int last;
        for(int d=2;d<=n;d=last+1)
        {
            last=n/(n/d);
            ret=ret-(last-d+1)*getsphi(n/d)%mod;
            if(ret<0)ret+=mod;
        }
        SPHI[n]=ret;
        return ret;
    }
    
    map<pair<int,int>,LL>S;
    LL gets(int n,int m)
    {
        if(m==0)return 0;
        if(m==1)return getphi(n);
        if(n==1)return getsphi(m);
        pair<int,int> P=make_pair(n,m);
        if(S.find(P)!=S.end())return S[P];
        
        int plen=0,p[10];
        int k=n,w=1;
        for(int i=2;i*i<=k;i++)
            if(k%i==0)
            {
                p[++plen]=i; w*=i;
                while(k%i==0)k/=i;
            }
        if(k!=1)p[++plen]=k, w*=k;
        //debug
        
        LL ret=0;
        int li=(1<<plen)-1;
        for(int zt=li;zt;zt=(zt-1)&li)
        {
            int d=1;
            for(int i=1;i<=plen;i++)
                if(zt&(1<<i-1))d*=p[i];
            ret=ret+getphi(w/d)*gets(d,m/d)%mod;
            if(ret>mod)ret-=mod;
        }
        ret=ret+getphi(w)*gets(1,m)%mod;
        if(ret>mod)ret-=mod;
        ret=(ret*(n/w))%mod;
        
        S[P]=ret;
        return ret;
    }
    
    int main()
    {
        getprime();
        int n,m;
        scanf("%d%d",&n,&m);
        LL ans=0;
        for(int i=1;i<=n;i++)
        {
            ans=ans+gets(i,m);
            if(ans>=mod)ans-=mod;
        }
        printf("%lld
    ",ans);
        
        return 0;
    }
  • 相关阅读:
    解析SparkStreaming和Kafka集成的两种方式
    不可不知的资源管理调度器Hadoop Yarn
    linux系统层面调优和常见的面试题
    OpenLayer加载百度坐标偏移问题解决(方案二)
    LeaFlet之GeoJson类介绍
    OpenLayer加载百度坐标偏移问题解决(方案一)
    LeaFlet迁徙图的制作
    OpenLayer4与mapV结合蜂巢图效果
    ArcGIS API For JS 实现右键菜单栏的功能
    OpenLayer4结合高德地图API实现交通态势的获取信息
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/10592752.html
Copyright © 2011-2022 走看看