@xiaoziyao
2021-07-07T03:11:35.000000Z
字数 2740
阅读 1457
数学 学习笔记
线性筛以的复杂度完成了数论函数的值域内求值,可是若要以更低的复杂度解决前缀求值,就要考虑更优的筛法了,例如杜教筛,Powerful Number,可是这两个筛法对函数都有较高的要求,于是我们要掌握更普适的筛子——min25筛。
min25筛可以以(一说,最新版本好像是)质数幂次上值为一个多项式的积性函数的前缀和。
题意:给定一个积性函数,满足,求
定义为的最小质因子,为第个素数。
实际上,min25筛解决的问题可以解决是阶为常数的任意多项式的情况,本题只是一种特殊情况。
我们考虑对质数和合数分开考虑,后面的合数枚举其最小质因子及其幂次:
前面枚举到是因为任意合数的一定小于等于,后面那个是为了不算入而算入。
考虑对于每个单项式,设其幂次为,设函数在素数上拟合,即。
考虑怎么从转移过来,不难发现时,否则要减去的贡献,而这个贡献容斥一下就是(考虑提出质因子,然后减去中多算的素数),即:
根据上面的素数合数分开算的式子,设
本题Powerful Number写法是的,但由于常数原因,我的min25比我的Powerful Number快一倍以上。
#include<stdio.h>#include<math.h>const int maxt=100005,mod=1000000007,inv2=(mod+1)/2,inv6=(mod+1)/6;int t,cnt,tot;long long n;int sum1[maxt],sum2[maxt],p[maxt],c[maxt],id[maxt][2],g1[maxt<<1],g2[maxt<<1];long long val[maxt<<1];inline int add(int a,int b){return a+b>=mod? a+b-mod:a+b;}int S(long long v,int k){if(p[k]>=v)return 0;int w=id[v<=t? v:(n/v)][v>t],res=add(add(g2[w],mod-sum2[k]),mod-add(g1[w],mod-sum1[k]));for(int i=k+1;i<=cnt&&1ll*p[i]*p[i]<=v;i++)for(long long j=1,mul=p[i];mul<=v;j++,mul*=p[i])res=add(res,1ll*mul%mod*((mul-1)%mod)%mod*(S(v/mul,i)+(j>1))%mod);return res;}int main(){scanf("%lld",&n),t=sqrt(n),c[1]=1;for(int i=2;i<=t;i++){if(c[i]==0)p[++cnt]=i,sum1[cnt]=add(sum1[cnt-1],i),sum2[cnt]=add(sum2[cnt-1],1ll*i*i%mod);for(int j=1;j<=cnt&&i*p[j]<=t;j++){c[i*p[j]]=1;if(i%p[j]==0)break;}}for(long long L=1,R;L<=n;L=R+1){long long v=n/L;int w=v%mod;R=n/v,val[++tot]=v,id[v<=t? v:R][v>t]=tot;g1[tot]=add(1ll*w*(w+1)%mod*inv2%mod,mod-1),g2[tot]=add(1ll*w*(w+1)%mod*(w+w+1)%mod*inv6%mod,mod-1);}for(int i=1;i<=cnt;i++)for(int j=1;j<=tot&&1ll*p[i]*p[i]<=val[j];j++){long long v=val[j]/p[i];int w=id[v<=t? v:(n/v)][v>t];g1[j]=add(g1[j],mod-1ll*p[i]*add(g1[w],mod-sum1[i-1])%mod);g2[j]=add(g2[j],mod-1ll*p[i]*p[i]%mod*add(g2[w],mod-sum2[i-1])%mod);}printf("%d\n",add(S(n,0),1));return 0;}
SP34096 DIVCNTK - Counting Divisors (general)
参考资料:Min_25筛 学习小记
