正题
Min_25筛是用来解决积性函数前缀和问题的。
这个积性函数要满足下面几个性质:
1.对于一个质数 p p p, f ( p ) f(p) f(p) 一定要是关于 p p p 的一个多项式
2.对于一个质数 p p p ,计算 f ( p c ) f(p^c) f(pc) 的时间不能太大。
例题满足上述两个条件:
因为对于一个大于 2 2 2 的质数 p p p ,有 f ( p ) = p − 1 f(p)=p-1 f(p)=p−1,而且 f ( p c ) f(p^c) f(pc) 很好计算。
现在只关注质数位置上的值,将 f ( x ) f(x) f(x) 直接看成 f ( x ) = x − 1 f(x)=x-1 f(x)=x−1
接下来把 f ( x ) f(x) f(x) 分开成多个函数相加,使得每一个函数都是完全积性的。
可以分成两个函数 f 1 ( x ) = 1 , f 2 ( x ) = x f_1(x)=1,f_2(x)=x f1(x)=1,f2(x)=x
对于每一个 x = ⌊ n i ⌋ x=\lfloor \frac n i \rfloor x=⌊in⌋ 先求: ∑ i = 1 x f 1 ( i ) [ i is a prime ] \sum_{i=1}^x f_1(i)[\text{i is a prime}] ∑i=1xf1(i)[i is a prime]
考虑埃式筛法并 D p Dp Dp ,设 g ( n , j ) g(n,j) g(n,j) 为前 n n n 个数,用了前 j j j 个质数进行埃式筛法后的函数值总和。
如果 p j 2 > n p_j^2>n pj2>n 那么说明它不会再筛去任何一个数,所以 g ( n , j ) = g ( n , j − 1 ) g(n,j)=g(n,j-1) g(n,j)=g(n,j−1)。
否则 g ( n , j ) = g ( n , j − 1 ) − f 1 ( P j ) [ g ( n / P j , j − 1 ) − ∑ i = 1 j − 1 f 1 ( P i ) ] g(n,j)=g(n,j-1)-f_1(P_j)[g(n/P_j,j-1)-\sum_{i=1}^{j-1}f_1(P_i)] g(n,j)=g(n,j−1)−f1(Pj)[g(n/Pj,j−1)−i=1∑j−1f1(Pi)]
求出来了 g g g 以后,考虑如何算答案。
设 S ( n , j ) S(n,j) S(n,j) 表示前n个数中,最小质因子 ≥ P j \geq P_j ≥Pj 的 f ( x ) f(x) f(x) 数的之和,注意这里的 f ( x ) f(x) f(x) 是原来的 f ( x ) f(x) f(x) 。
那么答案就是 S ( n , 1 ) + 1 S(n,1)+1 S(n,1)+1 。
有递推式 S ( n , j ) = ( g 2 ( n , ∣ p ∣ ) − g 1 ( n , ∣ p ∣ ) ) − ∑ i = 1 j − 1 f ( p i ) + ∑ k = j p k 2 ≤ n ∑ e = 1 p k e + 1 ≤ n S ( n / p k e , k + 1 ) ∗ f ( p e ) + f ( p e + 1 ) S(n,j)=(g_2(n,|p|)-g_1(n,|p|))-\sum_{i=1}^{j-1}f(p_i)+\sum_{k=j}^{p_k^2\leq n}\sum_{e=1}^{p_k^{e+1}\leq n}S(n/p_k^e,k+1)*f(p^e)+f(p^{e+1}) S(n,j)=(g2(n,∣p∣)−g1(n,∣p∣))−i=1∑j−1f(pi)+k=j∑pk2≤ne=1∑pke+1≤nS(n/pke,k+1)∗f(pe)+f(pe+1)
首先前面三个式子是算 ≤ n \leq n ≤n 的质数的 f ( x ) f(x) f(x) 值总和。由于小于 p j p_j pj 的质数不算,所以要减去他们的 f f f 值。后面就是枚举一个最小质因子为 p k e p_k^e pke,然后剩下的用 ≥ p k + 1 \geq p_{k+1} ≥pk+1 的质数去填,由于是积性函数,所以乘起来就是答案,再加上一个次方 f ( p k e + 1 ) f(p_k^{e+1}) f(pke+1) 即可。
这里直接递归的时间复杂度就是的 O ( n 3 4 log n ) O(\frac{n^{\frac{3}{4}}}{\log n}) O(lognn43) ,上面求 g g g 的时间复杂度也是这个。
常数不知道, 1 0 10 10^{10} 1010的数据跑了 597ms \text{597ms} 597ms。
有几个注意的地方:
1.我们筛质数只要筛到 n \sqrt n n 就可以了,因为两个东西都是要求的。
2.如果我递归的时候 p y p_y py 没有被筛到呢?这样的情况至多只会出现一层,就算不特判也对结果没有影响。
#include<bits/stdc++.h>
using namespace std;
long long n;
int m,data;
const long long mod=1e9+7;
bool vis[100010];
int id1[100010],id2[100010];
long long w[100010],g1[100010],g2[100010],sum[100010],p[100010];
void get_prime(){
data=sqrt(n);
for(int i=2;i<=data;i++){
if(!vis[i]) p[++p[0]]=i,sum[p[0]]=(sum[p[0]-1]+i)%mod;
for(int j=1;i*p[j]<=data;j++){
vis[i*p[j]]=true;
if(i%p[j]==0) break;
}
}
}
void get_2g(){
long long l=1,r,now;
while(l<=n){
r=n/(n/l);w[++m]=n/l;
if(w[m]<=data) id1[w[m]]=m;
else id2[n/w[m]]=m;
g1[m]=(w[m]-1)%mod;
g2[m]=((2+w[m])%mod)*((w[m]-1)%mod)%mod;
if(g2[m]&1) g2[m]+=mod;g2[m]/=2;
l=r+1;
}
for(int j=1;j<=p[0];j++){
for(int i=1;i<=m && p[j]*p[j]<=w[i];i++){
now=w[i]/p[j];
int id=(now<=data?id1[now]:id2[n/now]);
g1[i]=(g1[i]-g1[id]+j-1)%mod;(g1[i]+=mod)%=mod;
g2[i]=(g2[i]-p[j]*(g2[id]-sum[j-1])%mod)%mod;(g2[i]+=mod)%=mod;
}
}
}
long long S(long long x,int y){
if(x<=1 || p[y]>x) return 0;
int id=(x<=data?id1[x]:id2[n/x]);
long long ans=(g2[id]-g1[id]-sum[y-1]+y-1)%mod,p1,p2;(ans+=mod)%=mod;
if(y==1) (ans+=2)%=mod;
for(int k=y;k<=p[0] && p[k]*p[k]<=x;k++){
p1=p[k],p2=p1*p[k];
for(int e=1;p2<=x;e++,p1=p2,p2*=p[k])
(ans+=S(x/p1,k+1)*(p[k]^e)%mod+(p[k]^(e+1)))%=mod;
}
return ans;
}
int main(){
scanf("%lld",&n);
get_prime();get_2g();
printf("%lld\n",(S(n,1)+1)%mod);
}
本文详细介绍了Min_25筛算法,一种用于解决积性函数前缀和问题的有效方法。通过具体例题,展示了如何利用埃式筛法及动态规划思想优化计算过程,并给出了完整的C++实现代码。
890

被折叠的 条评论
为什么被折叠?



