听说这玩意玩爆洲阁筛???
按照惯例,放上fj_zzq的blog
Min_25筛可以解决一类积性函数求和问题,
筛质数
假设我们现在要对n以内的质数求和,
先线筛出小于
的所有质数,设第i个为
,共有
个质数,
为p的前缀和,
设函数:
设
显然,对于任意的x,
,我们要求的Ans就是
考虑转移:如果
,
否则:
就这样一直递推下去即可得出
不难发现这样还可以筛各种奇奇怪怪的东西,但还是不能筛任意的积性函数
积性函数求和
通过上面的方法可以求出大部分积性函数
,当x为质数时的和,现在要求的是:
考虑把上面的式子倒过来推,定义跟前面的一样:(可以用上面的S来预处理 )
设
这样
复杂度为:
可以发现对于第一个S,不用真的每次递归就直接这样递归下去,显然可以用一个for循环代替一个递归(见代码),
还可以不用递归的方式,常数还OK,
对于G也同理,
刚学一定要去做这几道题,学习正确筛法姿势,(点击传送至题解)
【LibreOJ #6053】简单的函数 //版子
【JZOJ 5683】【GDSOI2018模拟4.22】Prime //数据结构优化
【51NOD 1847】奇怪的数学题 //基本姿势
【51NOD 1965】奇怪的式子 //练手
Code
附上筛质数的代码
递归版:
LL Gg(LL n,int m)
{
if(n<N&&n<(LL)pr[m+1]*pr[m+1])return prs[n];
if(!m)return Sum(n);
for(;n<(LL)pr[m]*pr[m];--m);
LL ans=0;
for(;m;--m)ans=(ans-(Gg(n/pr[m],m-1)-prs[m-1])*pr[m])%mo;
return (ans+Sum(n))%mo;
}
非递归版:
void GS(LL n)
{
d[0]=0;
for(LL i=1,nx;i<=n;i=nx+1)
{
nx=n/(n/i);
LL t=n/i;
d[++d[0]]=t;
f[d[0]]=SUM(t,mo1)-1;
if(t<=M)id[t]=d[0];
else id1[n/t]=d[0];
}
fo(j,1,pr[0])
{
LL li=(LL)pr[j]*pr[j];
for(int i=1;d[i]>=li;++i)
{
LL t1=d[i]/pr[j];
int t=(t1>M)?id1[n/t1]:id[t1];
f[i]=(f[i]-(f[t]-prs[j-1])*(LL)pr[j])%mo1;
}
}
}