SP34112题解

好久没写$PN$筛了,回忆一下

什么是$PN$筛

以下节选自我的博客https://www.cnblogs.com/Eternal-Battle/p/15856794.html

考虑筛积性函数$f$前缀和

求函数$F(n)$

$F(n)=\sum_{i=1}^{n}f(i)$

时间复杂度$O(\sqrt{n})$

主要是基于$PN$的筛法

定义$:$

$PN:n$质因数分解,$n=\prod_{i=1}^{m}p_i^{e_i}$

当满足前$m$个质数都在$n$里面出现多于一次

性质$1:$

所有的$PN$都能表示为$a^2\times b^3$

显然任意一个大于$2$的数字可以被分成$2\times k_1+3\times k_2$

性质$2:$

有关时间复杂度为$O(\sqrt{n})$的性质

$n$以内的$PN$至多有$\sqrt{n}$个

对于函数$\sqrt{n/x^2}^3$在$[1,\sqrt{n}]$积分

$ \displaystyle\int _{1}^{\sqrt{n}} \sqrt{n/x^2}^3=\sqrt{n}$

然后得证

筛法$:$

首先需要构造一个函数$g$

满足在数字为质数时$g(p)=f(p)$

并且$G(n)=\sum_{i=1}^{n}g(i)$易得

构造函数$h=f/g,$这里$/$表示狄利克雷卷积除法

$h(1)=1$

对于素数$p$

$f(p)=g(1)h(p)+g(p)h(1)$

$f(p)=h(p)+g(p)$

$g(p)=f(p)$

$h(p)=0$

由于$h$是积性函数,且所有素数位置的$h$等于$0$,那么除了$PN$的位置,其余的位置都是$0$

还记得杜教筛是$h=f*g$

$f=g*h$

$F(n)=\sum_{i=1}^{n} f(i)$

$F(n)=\sum_{i=1}^{n}(g*h)(i)$

$F(n)=\sum_{i=1}^{n}\sum_{d|i}h(d)g(i/d)$

$F(n)=\sum_{d=1}^{n}h(d)\sum_{i=1}^{n/d}g(i)$

$F(n)=\sum_{d=1}^{n}h(d)G(n/d)$

由于除了$PN$的其他所有位置全部为$0$

那么$:$

$F(n)=\sum_{d=1,d\ is \ PN}^{n}h(d)G(n/d)$

显然的那么,可以在$O(\sqrt{n})$的时间内得到$F(n)$

只需要得到需要的$h(d)\times G(n/d)$

考虑$h$是积性函数,那么我们又知道$h(p)=0$

$h=f/g$

 

$f=g * h$

$f(p^c)=\sum_{i=0}^{c}g(p^i)h(p^{c-i})$

枚举$p$和指数$c$然后计算

一般过程$:$

$1.$构造$g$

$2.$构造快速求$G$的方法

$3.$计算$h(p^c)$

$4.$搜索$PN$,过程中累加答案

$5.$得到结果

对于这道题

构造函数$g$在质数位置等于$σ^*$

这个不用构造,$σ$是个天然的函数

我们需要有快速求$G$的方法

那么$G(n)=\sum_{i=1}^nσ(i)=\sum_{d=1}^nd\lfloor\frac{n}{d}\rfloor$

快速求$h=f/g$的方法发现我们$h(p^k)=-p(k=2)$,其余都是$0$

那么就套一套式子就好啦


$\sum_{i=1}^nf(i)=\sum_{i=1}^n(h*g)(i)$

$=\sum_{i=1}^n\sum_{d|i}h(d)g(\frac{i}{d})$

$=\sum_{d=1}^n h(d)\sum_{i|d}g(\frac{i}{d})$

$=\sum_{d=1}^n h(d)\sum_{i=1}^{n/d}g(i)$

$=\sum_{d=1}^n h(d)G(\frac{n}{d})$

自然的,$d$是$PN$啦

#define Eternal_Battle ZXK
#include<bits/stdc++.h>
#define ull unsigned long long
#define MAXN 10000000
#define ll long long
using namespace std;
ll pri[MAXN+5],Num[MAXN+5],Sum[MAXN],sd[MAXN+5],cnt,n;
bool vis[MAXN+5];
void Init()
{
     Num[1]=sd[1]=1;
     for(int i=2;i<=MAXN;i++)
     {
          if(!vis[i])
          {
               pri[++cnt]=i;
               Num[i]=i+1;
               sd[i]=i+1;
          }
          for(int j=1;j<=cnt&&i*pri[j]<=MAXN;j++)
          {
               vis[i*pri[j]]=1;
               if(i%pri[j]==0)
               {
                   Num[i*pri[j]]=Num[i]*pri[j]+1;
                   sd[i*pri[j]]=sd[i]/Num[i]*Num[i*pri[j]];
                   break;
               }
               Num[i*pri[j]]=pri[j]+1;
               sd[i*pri[j]]=sd[i]*(pri[j]+1);
          }
     }
     for(int i=1;i<=MAXN;i++)
     {
         Sum[i]=Sum[i-1]+sd[i];    
     }
}
ull C(ll n)
{
    if(n%2==0) return n/2ll*(n+1ll);
    else return (n+1ll)/2ll*n;
}
ull sol(ll n)
{
    if(n<=MAXN) return Sum[n];
    ull res=0;
    for(ll l=1,r;l<=n;l=r+1)
    {
        r=n/(n/l);
        res+=(n/l)*(C(r)-C(l-1));
    }
    return res;
}
ull dfs(ll n,ll m,ll val)
{
    ull res=val*sol(n);
    for(int j=m+1;j<=cnt&&pri[j]*pri[j]<=n;j++)
    {
        res+=dfs(n/pri[j]/pri[j],j,-val*pri[j]);
    }
    return res;
}
int main()
{
//    freopen("Reimu.in","r",stdin);
//    freopen("Reimu.out","w",stdout);
    Init();
    int T;
    cin>>T;
    while(T--)
    {
        scanf("%lld",&n);
        cout<<dfs(n,0ll,1ll)<<"\n";
    }
    
}

 

posted @ 2022-03-29 18:31  Authentic_k  阅读(38)  评论(0编辑  收藏  举报