yyb好神仙啊html
能够在\(O(\frac{n^{\frac 34}}{\log n})\)的时间内求积性函数\(f(x)\)的前缀和。数组
别问我为何是这个复杂度函数
要求\(f(p)\)是一个关于\(p\)的简单多项式,\(f(p^c)\)能够快速计算。spa
首先咱们须要对每一个\(x=\lfloor\frac ni\rfloor\)求出\(\sum_{i=1}^x[i是质数]f(i)\)。code
怎么求呢?htm
先线性筛出\(\sqrt n\)范围内的质数,设\(P_j\)表示从小到大第\(j\)个质数。blog
设\(g(n,j)=\sum_{i=1}^{n}[i \in P \ or\ \min(p)>P_j]f(i)\)get
说人话就是:\(i\)是质数,或者\(i\)的最小质因子大于\(P_j\),把\(1-n\)内知足条件的\(f(i)\)加起来就是\(g(n,j)\)。string
这个东西的实际含义是什么呢?能够参考一下埃氏筛法的运行过程。it
假设如今有\(n\)个数依次排开,第\(i\)个数是\(f(i)\),根据埃氏筛法的那套理论,每次选出一个质数,而后筛掉它的全部倍数。
会发现\(g(n,j)\)就是运行\(j\)次埃氏筛法后,没被筛掉的全部数之和加上全部的\(f(p)\)。
咱们要求的\(\sum_{i=1}^x[i是质数]f(i)\)其实就是\(g(x,|P|)\),其中\(|P|\)是质数集合的大小。
考虑\(g(n,j)\)的转移,分两种状况:
一、\(P_j^2>n\)。此时运行的第\(j\)次已经不会再筛掉任何数了(由于第\(j\)次运行中筛掉的最小的数是\(P_j^2\)),因此此时\(g(n,j)=g(n,j-1)\)。
二、\(P_j^2\le n\)。这时候咱们就要考虑哪些数被筛掉了。被筛掉的数必定含有质因子\(P_j\),且除掉\(P_j\)后最小的质因子会大于等于\(P_j\)。考虑减去\(f(P_j)\times g(\frac{n}{P_j},j-1)\),但在\(g(\frac{n}{P_j},j-1)\)中多减去了\(\sum_{i=1}^{j-1}f(P_i)\)这些最小质因子小于\(P_j\)的函数值,因此再把它们加上就行了。
因此总结起来就是:
\[g(n,j)=\begin{cases} g(n,j-1)&P_j^2\gt n\\ g(n,j-1)-f(P_j)[g(\frac{n}{P_j},j-1)-\sum_{i=1}^{j-1}f(P_i)]&P_j^2\le n\end{cases}\]
关于\(g(n,j)\)的初值问题:\(g(n,0)\)表示全部数的和,也就是把全部数都看成是质数带入\(f(p)\)的那个多项式中算出的结果。
由于最后只要求全部的\(g(x,|P|)\),因此在求的时候数组只开了一维。这样作的复杂度被证实是\(O(\frac{n^{\frac 34}}{\log n})\)的。
以\(f(x)=1\)即求\(n\)之内的质数个数为例:
for (int i=1,j;i<=n;i=j+1){ j=n/(n/i);w[++m]=n/i; if (w[m]<=Sqr) id1[w[m]]=m; else id2[n/w[m]]=m; g[m]=(w[m]-1)%mod; } for (int j=1;j<=tot;++j) for (int i=1;i<=m&&pri[j]*pri[j]<=w[i];++i){ int k=(w[i]/pri[j]<=Sqr)?id1[w[i]/pri[j]]:id2[n/(w[i]/pri[j])]; g[i]=(g[i]-g[k]+j-1)%mod;g[i]=(g[i]+mod)%mod; }
如今咱们已经对于\(x=\lfloor\frac ni\rfloor\)求出了\(\sum_{i=1}^x[i是质数]f(i)\)。
咱们设\(S(n,j)=\sum_{i=1}^n[\min(p)\ge P_j]f(i)\),也就是全部知足最小质因子大于等于\(P_j\)的\(f\)值之和。
那么最终的答案就是\(S(n,1)+f(1)\)。
鉴于质数的答案咱们已经算出来了,是\(g(n,j)-\sum_{i=1}^{j-1}f(P_i)\)。(由于要保证最小质因子大于等于\(P_j\)因此要把小于它的质数减掉)
考虑合数。咱们枚举这个合数的最小质因子及其出现次数,而后直接乘便可。
\[S(n,j)=g(n,|P|)-\sum_{i=1}^{j-1}f(P_i)+\sum_{k=j}^{P_k^2\le n}\sum_{e=1}^{P_k^{e+1}\le n}S(\frac{n}{P_k^e},k+1)\times f(P_k^e)+f(P_k^{e+1})\]
而后这个的复杂度也被证实是\(O(\frac{n^{\frac 34}}{\log n})\)的。
定义积性函数\(f(p^c)=p\oplus c\),求其前\(n\)项和。
会发现除了\(2\)之外的质数都知足\(f(p)=p\oplus 1=p-1\),因此能够分别计算出\(g(x,|P|)=\sum_{i=1}^x[i是质数]i\)以及\(h(x,|P|)=\sum_{i=1}^x[i是质数]1\)。
在处理\(S\)的时候,若是\(j=1\),就说明其中包含\(2\)这个因数,所以把答案\(+2\)便可。
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; #define ll long long const int N = 1e6+5; const int mod = 1e9+7; int Sqr,zhi[N],pri[N],sp[N],tot,m,id1[N],id2[N],g[N],h[N]; ll n,w[N]; void Sieve(int n){ zhi[1]=1; for (int i=2;i<=n;++i){ if (!zhi[i]) pri[++tot]=i,sp[tot]=(sp[tot-1]+i)%mod; for (int j=1;i*pri[j]<=n;++j){ zhi[i*pri[j]]=1; if (i%pri[j]==0) break; } } } int S(ll x,int y){ if (x<=1||pri[y]>x) return 0; int k=(x<=Sqr)?id1[x]:id2[n/x]; int res=(1ll*g[k]-h[k]-sp[y-1]+y-1)%mod;res=(res+mod)%mod; if (y==1) res+=2; for (int i=y;i<=tot&&1ll*pri[i]*pri[i]<=x;++i){ ll p1=pri[i],p2=1ll*pri[i]*pri[i]; for (int e=1;p2<=x;++e,p1=p2,p2*=pri[i]) (res+=(1ll*S(x/p1,i+1)*(pri[i]^e)%mod+(pri[i]^(e+1)))%mod)%=mod; } return res; } int main(){ scanf("%lld",&n); Sqr=sqrt(n);Sieve(Sqr); for (ll i=1,j;i<=n;i=j+1){ j=n/(n/i);w[++m]=n/i; if (w[m]<=Sqr) id1[w[m]]=m; else id2[n/w[m]]=m; h[m]=(w[m]-1)%mod; g[m]=((w[m]+2)%mod)*((w[m]-1)%mod)%mod; if (g[m]&1) g[m]+=mod;g[m]/=2; } for (int j=1;j<=tot;++j) for (int i=1;i<=m&&1ll*pri[j]*pri[j]<=w[i];++i){ int k=(w[i]/pri[j]<=Sqr)?id1[w[i]/pri[j]]:id2[n/(w[i]/pri[j])]; g[i]=(g[i]-1ll*pri[j]*(g[k]-sp[j-1])%mod)%mod;g[i]=(g[i]+mod)%mod; h[i]=(h[i]-h[k]+j-1)%mod;h[i]=(h[i]+mod)%mod; } printf("%d\n",S(n,1)+1); return 0; }