• Luogu6810 Convex Hull 凸包


    先写一下(Dirichlet) 前缀和

    就是求 (b_i=sumlimits_{j|i} a_j)

    (n le 2 imes 10^6)

    发现本质上 (a_i)(b_j) 有贡献是在唯一分解后 (a:c_kle b:c_k)

    可以筛完因数之后这样做:

    For(i,1,cnt)
    {
         for(reg int j=1;j*pri[i]*1ll<=n;++j) a[j*pri[i]]+=a[j];
    }
    

    具体的理解就是每次加的时候都是加上的这个因数上的前缀和

    (这种思想感觉挺妙的,不过感觉挺套路……)

    然后说这题的做法,一开始我把约数函数一拆,然后当场自闭,三张草稿纸瞬间交代

    保留着约数函数然后按照 简单的数学题 那个的做法可以得到:

    [sum_{T=1}^nsum_{g|T} d(g)mu(frac T g) sum_{i=1}^{lfloorfrac n T floor} sum_{j=1}^{lfloorfrac n T floor} d(iT)d(jT) ]

    (f=d * mu)

    (f(T)=sum_{g|T} f(g)mu(frac T g))

    其实可以用相关的组合式子给出 (f(x)=1) (直接唯一分解出来之后列式子就行了)

    然后要求的就是

    [sum_{T=1}^nsum_{i=1}^{lfloorfrac n T floor} sum_{j=1}^{lfloorfrac n T floor} d(iT)d(jT) ]

    (d) 直接筛,后面的部分用上面说的 (Dirichlet) 前缀和的转化(后缀和)

    时间复杂度降到了 (O(nlog log n)) (这里认为 (n,m) 同阶)

    #include<bits/stdc++.h>
    using namespace std;
    #define reg register
    #define For(i,a,b) for(reg int i=a;i<=b;++i)
    #define Down(i,a,b) for(reg int i=a;i>=b;--i)
    namespace yspm{
        inline int read()
        {
            int res=0,f=1; char k;
            while(!isdigit(k=getchar())) if(k=='-') f=-1;
            while(isdigit(k)) res=res*10+k-'0',k=getchar();
            return res*f;
        }
        const int N=5e7+10;
        int l[N],mod,pri[N/10],n,ans,d[N],cnt; 
        bool fl[N];
        inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
        inline int del(int x,int y){return x-y<0?x-y+mod:x-y;}
        inline int mul(int x,int y){return 1ll*x*y-1ll*x*y/mod*mod;}
        signed main()
        {
            freopen("sum.in","r",stdin);
            freopen("sum.out","w",stdout);
            n=read(); mod=read(); 
            d[1]=1; 
            for(reg int i=2;i<=n;++i)
            {
                if(!fl[i]) pri[++cnt]=i,d[i]=2,l[i]=1; 
                for(reg int j=1;j<=cnt&&1ll*pri[j]*i<=n;++j)
                {
                    fl[i*pri[j]]=1;
                    if(i%pri[j]==0)
                    {
                        d[pri[j]*i]=d[i]/(l[i]+1)*(l[i]+2);
                        l[i*pri[j]]=l[i]+1;
                        break;
                    }else d[pri[j]*i]=d[i]*2,l[i*pri[j]]=1;
                }
            }
            for(reg int i=1;i<=cnt;++i) for(reg int j=n/pri[i];j>=1;--j) d[j]=add(d[j],d[j*pri[i]]);
            For(i,1,n) ans=add(ans,mul(d[i],d[i])); 
            printf("%d
    ",ans);
            return 0;
        }
    }
    signed main(){return yspm::main();}
    
  • 相关阅读:
    SpringBoot发送邮箱验证码
    判断一个数是否为2的整数次幂
    [模板] 虚树 && bzoj2286-[Sdoi2011]消耗战
    [模板] K-D Tree
    [模板] 平衡树: Splay, 非旋Treap, 替罪羊树
    对于约数个数上界的估计
    luogu3702-[SDOI2017]序列计数
    [模板] 线性基
    [模板] 区间mex && 区间元素种数
    bzoj4367-[IOI2014]holiday假期
  • 原文地址:https://www.cnblogs.com/yspm/p/13681117.html
Copyright © 2020-2023  润新知