Min25 筛与 Powerful Numbers
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(\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\) 个质数且该轮已筛完的状态。
于是我们枚举当前应该筛掉哪些数,有
\]
我们当前要筛掉 \(\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
模板题。对于所有奇质数 \(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}\) 有这样美好的性质,我们可以把原来的式子转换一下:
&\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)\)。
我们多列几项:
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;
}
Min25 筛与 Powerful Numbers的更多相关文章
- CodeForces - 83D:Numbers (数学&递归 - min25筛 )
pro:给定三个整数L,R,P求[L,R]区间的整数有多少个是以P为最小因子的.L,R,P<2e9; sol: 一: 比较快的做法是,用函数的思想递归. 用solve(N,P)表示求1到N有多少 ...
- 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\) 的次大质 ...
- BZOJ-5244 最大真因数(min25筛)
题意:一个数的真因数指不包括其本身的所有因数,给定L,R,求这个区间的所有数的最大真因数之和. 思路:min25筛可以求出所有最小因子为p的数的个数,有可以求出最小因子为p的所有数之和. 那么此题就是 ...
- loj#6235. 区间素数个数(min25筛)
题意 题目链接 Sol min25筛的板子题,直接筛出\(g(N, \infty)\)即可 筛的时候有很多trick,比如只存\(\frac{N}{x}\)的值,第二维可以滚动数组滚动掉 #inclu ...
- 「学习笔记」Min25筛
「学习笔记」Min25筛 前言 周指导今天模拟赛五分钟秒第一题,十分钟说第二题是 \(\text{Min25}\) 筛板子题,要不是第三题出题人数据范围给错了,周指导十五分钟就 \(\text{AK ...
- [总结] min-25筛
再不写总结我又会忘掉啊啊啊啊啊啊啊啊啊 这个\(min-25\)筛主要用来求一个积性函数的前缀和,就像这样\[\sum_{i=1}^n f(i)\] 不过这个积性函数要满足两个条件:质数\(p\)的函 ...
- min25筛学习总结
前言 杜教筛学了,顺便把min25筛也学了吧= =刚好多校也有一道题需要补. 下面推荐几篇博客,我之后写一点自己的理解就是了. 传送门1 传送门2 传送门3 这几篇写得都还是挺好的,接下来我就写下自己 ...
- Min25筛
Min25筛 我是沙雕... 从yyb博客蒯的 要求:\(\sum_{i=1}^nF(x)\) \(F(x)\)是积性函数. \(Min25\)筛能用的前提:质数处的\(f(p)\)值是关于\(p\) ...
- 莫比乌斯反演/线性筛/积性函数/杜教筛/min25筛 学习笔记
最近重新系统地学了下这几个知识点,以前没发现他们的联系,这次总结一下. 莫比乌斯反演入门:https://blog.csdn.net/litble/article/details/72804050 线 ...
随机推荐
- rman备份出现ORA-19625
[oracle@hear adump]$ rman target / Recovery Manager: Release 11.2.0.4.0 - Production on Mon Jun 17 0 ...
- 分层条件关系网络在视频问答VideoQA中的应用:CVPR2020论文解析
分层条件关系网络在视频问答VideoQA中的应用:CVPR2020论文解析 Hierarchical Conditional Relation Networks for Video Question ...
- ES6函数参数
之前在看Vue2.0的时候,就被很多的箭头函数困扰,一直不知道是怎么回事,虽然箭头函数四个字在我耳边一直转圈,今天小编整理整理箭头函数里面的常见用法和表现形式,在这个Vue3.0已经到来的一段时间,希 ...
- mybatis——一级缓存、二级缓存
一.Mybatis缓存 ● MyBatis包含一个非常强大的查询緩存特性,它可以非常方便地定制和配置缓存.绶存可以极大的提升查询效率. ● MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存 ...
- 好用的Java工具类库,GitHub星标10k+你在用吗?
简介 Hutool是Hu + tool的自造词,前者致敬我的"前任公司",后者为工具之意,谐音"糊涂",寓意追求"万事都作糊涂观,无所谓失,无所谓得& ...
- MQTT 协议是个啥?这篇文章告诉你!
文章首发于我的公众号「程序员cxuan」,欢迎大家关注呀- 说到做到! 之前有位读者给我留言说想要了解一下什么是 MQTT 协议,顺便还把我夸了一把,有点不好意思啦. 那么读者的要求必须要满足啊,所以 ...
- JNI相关笔记 [TOC]
JNI相关笔记 目录 JNI相关笔记 1 生成native code所需要的头文件 2 JNI提供的一些函数和方法 3 局部引用,全局引用,全局弱引用. 4 异常 1 生成native code所需要 ...
- 关于MySql数据库误操作数据找回的办法
先讲个事,前段时间,系统长时间不用的一个功能被开放出来了,想当然的我没有在测试平台上测试,直接操作了正式系统(的确是我不严谨),导致好多数据异常,页面展示错乱了.于是我想到的第一个就是进行备份还原.项 ...
- split截取字符串
一.根据单个分隔字符用split截取字符串:string st="GT123_1";split代码:string[] sArray=st.split("_"); ...
- go语言结构体内存对齐
cpu要想从内存读取数据,需要通过地址总线,把地址传输给内存,内存准备好数据,输出到数据总线,交给cpu,如果地址总线只有8根,那这个地址就只有8位可以表示[0,255]256个地址,因为表示不了更多 ...