Min25 筛与 Powerful Numbers

Min25 筛

大喊一声 Min25 NB!!!

这是一个非常神奇的东西,用于求更加普遍的积性函数的前缀和。

比如我们要求 \(\sum_{i=1}^{n}f(i)\),其中 \(f(1)=1\)。我们考虑将质数与合数分开考虑。(由于 \(1\) 这俩都不是,我们先不考虑)所以答案就等于质数的答案加上合数的答案再加上 \(f(1)\)。

但是这样还是不够优美。因为合数的范围太广泛了,我们考虑对于每个质数再分组。

在这里,我们设 \(\sigma(x)\) 为 \(x\) 的最小质因子。

定义 \(S(n,k)\) 表示第 \(2\) 到第 \(n\) 个数中,\(\sigma (x) \ge pri_k\) 的数的 \(f(x)\) 之和。其中 \(p_k\) 表示第 \(k\) 大的质数。显然有 \(\max{p_k}\le \sqrt n\)。这也决定了用到的质数不会很多。

我们同样将质数和合数分开考虑。由于 \(f\) 是积性函数,所以有 \(f(p_1^{k_1})f(p_2^{k^2})=f(p_1^{k_1}p_2^{k^2})\)。这启发我们可以枚举质数幂进行转移。

所以有

\[S(n,k)=\sum_{i\ge k,p_i\le n}f(p_i)+\sum_{j\ge k}\sum_{e\ge 1,p_j^{e+1}\le n}(f(p_j^e)\cdot S(\lfloor\frac{n}{p_j^e}\rfloor,j+1)+f(p_j^{e+1}))
\]

稍微解释一下就是前半部分是满足条件的质数的和。 \(S(\lfloor\frac{n}{p_j^e}\rfloor,j+1)\) 中的数的最小质因子 \(\ge p_{j+1}>p_j\),所以这里我们枚举一个没有出现过的质数幂乘上去。同时由于 \(f\) 是积性函数,我们要对这一部分值全部乘上 \(f(p_j^e)\)。同时注意答案中没有包含 \(f(p_j^{e+1})\) 这一项(因为我们是从 \(2\) 开始计数的,在前面做乘法的时候由于 \(1\) 的缺失导致 \(p_j^e\) 的缺失),要补上。

最后的答案就是 \(S(n,1)+f(1)\)。

这个东西可以递归进行计算,但是显然需要一些条件:

  • \(f(p)\) 是一个关于 \(p\) 的项数较小的多项式或可以快速求值。
  • \(f(p^c)\) 能够较方便的计算,即质数幂处的 \(f\) 值能够较方便的计算。
  • \(\sum_{i\ge k,p_i\le n}f(p_i)\) 能够快速计算。然后这东西可以拆成前缀和然后作差。\(i\le k\) 的部分由于 \(k\) 很小,且 \(f(p)\) 是低次多项式,可以在线性筛的时候顺便处理掉,问题转化为快速求出当 \(n\) 较大时质数处的 \(f\) 的前缀和。

第一个和第二个条件我们似乎没有什么办法克服,全看出题人是否良心。

我们来考虑能否快速求出质数处的 \(f\) 的前缀和,设 \(sum_k=\sum_{p\le k,p\in \mathrm{prime}}f(p)\)。

首先对上面的递推式进行观察,会发现我们需要的 \(sum_k\) 的个数其实很少,都是形如 \(sum_{\lfloor\frac n x \rfloor}\) 这样的值。

显然可以证明这样的下标最多只有 \(O(\sqrt n )\) 个,实在不放心可以打个表试试。

然后我们发现,此时我们对于合数的值并不关心,即我们只需要构造一个 \(g\) 使得 \(g(p)=f(p)\),求出 \(g\) 的前缀和后再将合数位置处的 \(g\) 的值剪掉,同样能够得到我们想要得到答案。

我们可以通过构造使得 \(g\) 是一个完全积性函数,即对于任意 \(i,j\) 均有 \(g(i)g(j)=g(ij)\)。

设 \(G(n,k)\) 表示 \(\forall x\in [2,n],x\in \mathrm{prime} \or \sigma(x)> p_k\) 这样的 \(x\) 的 \(g(x)\) 之和。其实这个状态非常类似与我们在进行埃氏筛的时候,枚举到第 \(k\) 个质数且该轮已筛完的状态。

于是我们枚举当前应该筛掉哪些数,有

\[G(n,k)=G(n,k-1)-g(p_k)(G(\lfloor \frac{n}{p_k}\rfloor,k-1)-sum_{p_{k-1}})
\]

我们当前要筛掉 \(\sigma (x)=p_k\) 的合数。

当 \(p_k^2\ge n\) 时,显然我们无数可筛。此时 \(G(n,k)=G(n,k-1)\)。

当 \(p_k^2\le n\) 时,由于我们构造了 \(g\) 使其为完全积性函数,所以减掉 \(g(p_k)G(\lfloor \frac{n}{p_k}\rfloor,k-1)\),就相当于减掉了这一部分合数的 \(g(x)\) 之和。但是根据定义,\(G(\lfloor \frac{n}{p_k}\rfloor,k-1)\) 包含了一部分 \(\le p_k\) 的质数,这样会使得 \(\sigma (x)\neq p_k\),所以要加上 \(g(p_k)sum_{p_{k-1}}\)。

显然答案为 \(G(n,\mathrm{cnt})\),其中 \(\mathrm{cnt}\) 为 \(\le \sqrt n\) 的质数个数。

然后根据前文所提到的,我们最后需要的只有 \(O(\sqrt n)\) 个 \(G(N,\mathrm{cnt})\),直接做就完事了。

初始状态也非常显然:\(G(n,0)=\sum_{i=1}^{n}g(i)\)。

所以我们构造的这个函数应该需要比较好算。

事实上若 \(f(x)\) 是一个 \(k\) 次多项式,我们有\(f(x)=\sum_{i=0}^ka_ix^i\)。

我们把 \(f(x)\) 拆开,令 \(g_k(x)=x^k\),则有 \(f(x)=\sum_{i=0}^ka_ig_i(x)\)。

显然每一个 \(g_k\) 都是一个完全积性函数,而且它的前缀和也非常好算(拉格朗日插值即可),所以我们对每一个 \(g_k\) 筛一遍再合并即可。

Q:如果 k 很大咋办呢?

A:k 很大... k 很大...... 自求多福。——zzq

然后我们就做完了。

我也不太会证明复杂度,反正就能跑 \(10^{10}\),\(10^{11}\) 可以抢救一下。

实际上这个算法比杜教筛快,限制还比杜教筛小。

杜教筛,永远的垃圾。——zzq

「LOJ 6053」 简单的函数

模板题。对于所有奇质数 \(p\),有 \(f(p)=p-1\)。我们先令 \(f(p)=p\) 然后再减掉素数个数即可。

同时注意考虑唯一的偶质数 \(2\) 的贡献。

/*---Author:HenryHuang---*/
/*---Never Settle---*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=5e5+5;
const ll p=1e9+7;
const ll inv2=5e8+4;
ll n,P;
ll pri[maxn],pp[maxn],cnt;
ll id[maxn],id2[maxn],dex;
ll w[maxn],g[maxn],h[maxn],f[maxn];
ll pre[maxn];
ll F(ll x,ll y){
return x^y;
}
void init(){
for(ll i=2;i<=P;++i){
if(!pp[i]) pri[++cnt]=i,pre[cnt]=(pre[cnt-1]+i)%p;
for(ll j=1;j<=cnt&&pri[j]*i<=P;++j){
pp[pri[j]*i]=1;
if(i%pri[j]==0) break;
}
}
} ll getid(ll x){
if(x<=P) return id[x];
else return id2[n/x];
}
void prework(){
for(ll l=1,r,v;l<=n;l=r+1){
v=(n/l),r=(n/v);
if(v<=P) id[v]=++dex;
else id2[r]=++dex;
w[dex]=v;v%=p;
g[dex]=1ll*(2+v)*(v-1+p)%p*inv2%p;
h[dex]=(v-1);
}
for(ll i=1;i<=cnt;++i){
ll z=pri[i];
for(ll j=1;j<=dex&&z*z<=w[j];++j){
ll op=getid(w[j]/z);
g[j]=(g[j]-z*(g[op]-pre[i-1]+p)%p+p)%p;
h[j]=(h[j]-h[op]+i-1+p)%p;
}
}
for(ll j=1;j<=dex;++j) f[j]=(g[j]-h[j]+p)%p;
}
ll solve(ll x,ll i){
if(x<=1||pri[i]>x) return 0;
ll ans=f[getid(x)]-(pre[i-1]-(i-1));
if(i==1) ans+=2;
for(ll j=i;j<=cnt&&pri[j]*pri[j]<=x;++j){
ll r=pri[j];
for(ll e=1;r*pri[j]<=x;++e,r*=pri[j]){
ans=(ans+F(pri[j],e)*solve(x/r,j+1)+F(pri[j],e+1))%p;
}
}
return ans;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;P=sqrt(n+0.5);
init();
prework();
cout<<(solve(n,1)+1)%p<<'\n';
return 0;
}


Powerful Numbers

这也是一个非常神奇的东西,用于求极为特殊的积性函数的前缀和。

比如我们要求 \(\sum_{i=1}^{n}f(i)\),但是这个 \(f\) 非常神奇,其满足 \(f(1)=1,f(p)=1\),其中 \(p\) 为质数。

然后我们发现这和我们一个非常喜欢的积性函数 \(g(x)=1\) 非常像,大家都会求它的前缀和。它们在质数处的值是一样的,即 \(f(p)=g(p)\)。

我们尝试构造一个积性函数 \(h(x)\) 使得 \(\sum_{ij=x}h(i)g(j)=f(x)\)。

首先由 \(f(1)=1\) 可推出 \(h(1)=1\)。

再由 \(f(p)=1\) 可以推出 \(f(p)=h(1)g(p)+h(p)g(1)=1+h(p)\)。

从这里我们发现 \(h(p)=0\),也就是说,\(h\) 在质数位置上的值均为 \(0\)。

再进一步,由于 \(h\) 是一个积性函数,由 \(h(p_ip_j)=h(p_i)h(p_j)\) 有 \(h\) 在所有存在一个质数因子的次数 \(=1\) 的位置均为 \(0\)。

换句话说,只有当一个数,其包含的所有质因子的次数均 \(\ge 2\),\(h\) 才会有值。而这样的数,就被称为 \(\texttt{Powerful Numbers}\)。

可以证明其个数为 \(O(\sqrt n)\) 的。你实在不放心可以打个表跑一跑。

如何求?枚举质因子爆搜就完事了,但需要注意必要的剪枝。

由于 \(\texttt{Powerful Numbers}\) 有这样美好的性质,我们可以把原来的式子转换一下:

\[\begin{aligned}
&\sum_{x=1}^nf(x)\\
=&\sum_{x=1}^n\sum_{ij=x}h(i)g(j)\\
=&\sum_{i=1}^nh(i)\sum_{j=1}^{\lfloor \frac n i \rfloor}g(j)
\end{aligned}
\]

本质上我们需要求出所有 \(ij\le n\) 的 \(h(i)g(j)\),所以换个方式枚举即可。

现在我们的问题就变成了:求 \(\texttt{Powerful Numbers}\) 的 \(h(x)\),以及求 \(g\) 的前缀和。

在这个例子中,\(g\) 的前缀和大家都会求。即 \(\sum_{i=1}^ng(i)=n\)。

问题变为如何快速求出 \(h(x)\)。

事实上你经常可以通过质数幂处的 \(f(p^c)\) 来猜出 \(h(p^c)\) 的值,又因为其是一个积性函数,你就能在爆搜的同时把答案求出来了。

事实上如果你猜不出来可能需要把质数幂处的值全部整出来然后暴力多项式除法?

不管能猜就猜猜不出来再说

总结一下,能够用这种筛法的条件

  • 你能构造出一个积性函数 \(g\) 使得 \(f(p)=g(p)\)。
  • 这个 \(g\) 的前缀和比较好算。

Example

令 \(f(x)=p_1^{\lfloor \frac{c_1}{2}\rfloor}p_2^{\lfloor \frac{c_2}{2}\rfloor}\cdots p_k^{\lfloor \frac{c_k}{2}\rfloor}\),其中 \(p\) 为对 \(x\) 唯一分解后的质因子,\(c\) 为每个质因子的次数。求 \(\sum_{i=1}^nf(i)\)。


我们发现这东西显然是满足 \(f(p)=1\) 的,所以非常愉快地令 \(g(x)=1\)。

现在问题转变为求 \(h(x)\)。

我们多列几项:

\[\begin{aligned}
f(1)=h(1)g(1)&\rightarrow h(1)=1\\
f(p)=h(1)g(p)+h(p)g(1)&\rightarrow h(p)=0\\
f(p^2)=h(1)g(p^2)+h(p)g(p)+h(p^2)g(1)&\rightarrow h(p^2)=p-1\\
f(p^3)=h(1)g(p^3)+h(p)g(p^2)+h(p^2)g(p)+h(p^3)g(1)&\rightarrow h(p^3)=0\\
f(p^4)=h(1)g(p^4)+h(p)g(p^3)+h(p^2)g(p^2)+h(p^3)g(p)+h(p^4)g(1)&\rightarrow h(p^4)=p^2-p=p(p-1)\\
\end{aligned}
\]

我觉得列到这里已经差不多能猜出来了。

当 \(k\) 为奇数时,\(h(p^k)=0\)。

当 \(k\) 为 \(2\) 时,\(h(p^k)=p-1\)。

当 \(k\) 为其他偶数时,\(h(p^k)=(p-1)p^{\frac{k-2}{2}}\)。

然后算就完事了。

时间复杂度为 \(O(\sqrt n )\)。事实上由于当 \(k\) 是奇数时 \(h(p^k)\) 均为 \(0\),所以可以进一步剪枝。

/*---Author:HenryHuang---*/
/*---Never Settle---*/
#include<bits/stdc++.h>
using namespace std;
const int maxn=3.5e6+5;
typedef unsigned long long ll;
ll pri[maxn],pp[maxn],p,cnt;
void init(){
for(ll i=2;i<=p;++i){
if(!pp[i]) pri[++cnt]=i;
for(ll j=1;j<=cnt&&pri[j]*i<=p;++j){
pp[pri[j]*i]=1;
if(i%pri[j]==0) break;
}
}
}
ll ans,n,owo;
void dfs(ll num,ll now,ll phi){
if(now==cnt+1||num*pri[now]>n||num*pri[now]*pri[now]>n){
ans+=phi*(n/num);
++owo;
return ;
}
dfs(num,now+1,phi);
for(int i=2;;i+=2){
num*=pri[now];
if(num>n) break;
num*=pri[now];
if(num>n) break;
if(i==2) phi*=(pri[now]-1);
else phi*=pri[now];
dfs(num,now+1,phi);
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int T;cin>>T;
p=sqrt(1e13);
init();
while(T--){
cin>>n;ans=0;
dfs(1,1,1);
cout<<ans<<'\n';
}
return 0;
}

Submit Link

Min25 筛与 Powerful Numbers的更多相关文章

  1. CodeForces - 83D:Numbers (数学&递归 - min25筛 )

    pro:给定三个整数L,R,P求[L,R]区间的整数有多少个是以P为最小因子的.L,R,P<2e9; sol: 一: 比较快的做法是,用函数的思想递归. 用solve(N,P)表示求1到N有多少 ...

  2. LOJ# 572. 「LibreOJ Round #11」Misaka Network 与求和(min25筛,杜教筛,莫比乌斯反演)

    题意 求 \[ \sum_{i = 1}^{n} \sum_{i = 1}^{n} f(\gcd(i, j))^k \pmod {2^{32}} \] 其中 \(f(x)\) 为 \(x\) 的次大质 ...

  3. BZOJ-5244 最大真因数(min25筛)

    题意:一个数的真因数指不包括其本身的所有因数,给定L,R,求这个区间的所有数的最大真因数之和. 思路:min25筛可以求出所有最小因子为p的数的个数,有可以求出最小因子为p的所有数之和. 那么此题就是 ...

  4. loj#6235. 区间素数个数(min25筛)

    题意 题目链接 Sol min25筛的板子题,直接筛出\(g(N, \infty)\)即可 筛的时候有很多trick,比如只存\(\frac{N}{x}\)的值,第二维可以滚动数组滚动掉 #inclu ...

  5. 「学习笔记」Min25筛

    「学习笔记」Min25筛 前言 周指导今天模拟赛五分钟秒第一题,十分钟说第二题是 \(\text{Min25}​\) 筛板子题,要不是第三题出题人数据范围给错了,周指导十五分钟就 \(\text{AK ...

  6. [总结] min-25筛

    再不写总结我又会忘掉啊啊啊啊啊啊啊啊啊 这个\(min-25\)筛主要用来求一个积性函数的前缀和,就像这样\[\sum_{i=1}^n f(i)\] 不过这个积性函数要满足两个条件:质数\(p\)的函 ...

  7. min25筛学习总结

    前言 杜教筛学了,顺便把min25筛也学了吧= =刚好多校也有一道题需要补. 下面推荐几篇博客,我之后写一点自己的理解就是了. 传送门1 传送门2 传送门3 这几篇写得都还是挺好的,接下来我就写下自己 ...

  8. Min25筛

    Min25筛 我是沙雕... 从yyb博客蒯的 要求:\(\sum_{i=1}^nF(x)\) \(F(x)\)是积性函数. \(Min25\)筛能用的前提:质数处的\(f(p)\)值是关于\(p\) ...

  9. 莫比乌斯反演/线性筛/积性函数/杜教筛/min25筛 学习笔记

    最近重新系统地学了下这几个知识点,以前没发现他们的联系,这次总结一下. 莫比乌斯反演入门:https://blog.csdn.net/litble/article/details/72804050 线 ...

随机推荐

  1. VMware Tanzu Kubernetes Grid 1.3 发布 - VMware 构建、签名和支持的开源 Kubernetes 容器编排平台的完整分发版

    Tanzu Kubernetes 集群是由 VMware 构建.签名和支持的开源 Kubernetes 容器编排平台的完整分发版.可以通过使用 Tanzu Kubernetes Grid 服务在主管集 ...

  2. JMeter36个内置函数及11个新增函数介绍

    JMeter内置了36个函数,这些函数可以通过函数助手进行编辑和测试.了解这些函数,不仅能提高JMeter的使用熟练度,也有助于知晓测试工具或测试框架通用的函数有哪些,在自主设计时,作为参考借鉴. J ...

  3. GO学习-(5) Go语言基础之基本数据类型

    Go语言中有丰富的数据类型,除了基本的整型.浮点型.布尔型.字符串外,还有数组.切片.结构体.函数.map.通道(channel)等.Go 语言的基本类型和其他语言大同小异. 基本数据类型 整型 整型 ...

  4. .NET Core Web API使用HttpClient提交文件的二进制流(multipart/form-data内容类型)

    需求背景: 在需要通过服务端请求传递文件二进制文件流数据到相关的服务端保存时,如对接第三方接口很多情况下都会提供一个上传文件的接口,但是当你直接通过前端Ajax的方式将文件流上传到对方提供的接口的时候 ...

  5. docker磁盘空间清理办法

    docker磁盘空间清理办法 前段时间遇到docker磁盘空间太少,无法写入数据的问题.起因是因为我在本地(Mac Pro)运行了多个mysql容器,并且导入了一部分线上数据,最后还没导入完毕就已经没 ...

  6. Gamma矫正技术

    Gamma矫正技术 一. gamma校正背景 在电视和图形监视器中,显像管发生的电子束及其生成的图像亮度并不是随显像管的输入电压线性变化,电子流与输入电压相比是按照指数曲线变化的,输入电压的指数要大于 ...

  7. 【NX二次开发】Block UI 曲线收集器

    属性说明 属性   类型   描述   常规           BlockID    String    控件ID    Enable    Logical    是否可操作    Group    ...

  8. Netty 框架学习 —— EventLoop 和线程模型

    EventLoop 接口 Netty 是基于 Java NIO 的,因此 Channel 也有其生命周期,处理一个连接在其生命周期内发生的事件是所有网络框架的基本功能.通常来说,我们使用一个线程来处理 ...

  9. ES6中的Generator函数

    今天小编发现一个es6中的新概念,同时也接触到了一个新关键字yeild,下面我就简单和大家聊聊es6中的generator函数.大家还可以关注我的微信公众号,蜗牛全栈. 一.函数声明:在functio ...

  10. jQuery筛选选择器

    <!DOCTYPE html><html><head>    <meta http-equiv="Content-type" conten ...