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();}
原文地址:https://www.cnblogs.com/yspm/p/13681117.html