目标:求 i=1∑NF(x),F(x) 积性并在素数处能拆成若干完全积性函数的和。
一些约定:fac(x) 表示 x 最小质因子,pi 表示第 i 个素数, ω(i) 表示 i 的质因子个数,n/i 表示 ⌊in⌋,P 表示素数集合。
再定义一个 H(n)=pi≤n∑F(pi),同时提醒读者注意文中 n 与 N 的区别。
Part 1 最小质因子分类
定义一个 S(n,k)=fac(x)≥pk∑nF(x),所求即为 S(N,1)。(Tip:fac(1)=+∞)
需要做个递推式出来,考虑将其按照 fac 分类来计算。具体而言枚举 pi 及其次数 c,表示我要计算 fac(x)=pi 且其次数为 c 的 ∑F(x):
S(n,k)=1+i=k∑ω(n)c=1∑pic≤nF(pic)S(n/pic,i+1)
观察到 pi≥n 时,有贡献的只有 pi 一个数,那就分类计算:
S(n,k)=1+i=k∑ω(n)c=1∑pic≤nF(pic)S(n/pic,i+1)+H(n)−H(n)
这样的好处是只用计算 pk≤N 的状态。前面一半递归计算,H(x) 可以暴力求,复杂度显然有一个 O(logNN) 的上界但跑不满(听说在 N≤1013 时是 O(logNN0.75) 的),问题转化为对每个 x=N/i 求出 H(x)。
Part 2 质数点值和
把 F 在素数处的取值拆成若干完全积性函数的和来算,假设拆出来的完全积性函数是 f1(x),f2(x)…。定义一个 hk(x)=pi≤n∑fk(pi),则 H(x) 可以用 ∑khk(x) 来算,下面考虑 h(x) 与 f(x)。
令 g(n,k)=x=1∑n[x∈P∨fac(x)>pk]f(x),显然 h(n)=g(n,ω(n))。
g 的第 k 列可以由第 k−1 列递推而来,具体而言 g(n,k) 是由 g(n,k−1) 去掉了 fac(x)=pk 的合数得到,利用 f 的完全积性可以得到以下递推式:
g(n,k)={g(n,k−1)g(n,k−1)−f(pk)(g(n/pk,k−1)−h(pk−1))(pk>n)(pk≤n)
上面一半没卵用,只需要递推出 pk≤N 的点值即可,状态数一共 O(logNN0.75) 个,线性筛出 N 以内的 f 与 h 即可求出所有 x=n/i 的 h(x)。
代码实现
总而言之,认为复杂度是 O(run 1e10 is ok) 就行,大概。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| #include<bits/stdc++.h> #define FOR(i,a,b) for(int i=a,i##i=b;i<=i##i;++i) using namespace std; typedef long long ll; const int N=2e5+7,mod=1e9+7; ll n,m,vl[N],g1[N],g2[N]; int isp[N],C,P[N],ct,o[N]; int id(ll x){return x<=m?x:C+1-n/x;} ll S(ll n,int k){ if(P[k-1]>=n)return 1; ll D=max((int)sqrt(n),P[k-1]),su=1+g2[id(n)]-g1[id(n)]-g2[D]+g1[D]; FOR(i,k,o[D])for(ll p=P[i];p<=n;p*=P[i]){ (su+=p%mod*(p%mod-1ll)%mod*S(n/p,i+1))%=mod; } return su; } int main(){ cin>>n,m=sqrt(n),C=2*m; isp[1]=1; FOR(i,2,m){ o[i]=o[i-1]; if(!isp[i])++o[P[++ct]=i]; for(int j=1;j<=ct&&i*P[j]<=m;++j){ isp[i*P[j]]=1; if(i%P[j]==0)break; } } FOR(i,1,C){ ll p=(vl[i]=i<=m?i:n/(C+1-i))%mod; g1[i]=p*(p+1ll)/2%mod,g2[i]=(p*2+1ll)*g1[i]%mod*(mod+1)/3%mod; } FOR(k,1,o[m])for(ll i=C,p=P[k];1ll*p*p<=vl[i];--i){ ll E=id(vl[i]/p); (g1[i]+=p*(g1[p-1]-g1[E]))%=mod; (g2[i]+=(g2[p-1]-g2[E])*p%mod*p)%=mod; } cout<<(S(n,1)+mod)%mod; return 0; }
|