张俊的课件如是说:
一个对单个n有效的方法:
f[n]表示n以内的素数个数
c[i]表示第i个素数
g[n][m]表示n以内不被c[1..m]整除的数的个数
(1)
f[n]=f[sqrt(n)]+g[n][f[sqrt(n)]]-1
//大于sqrt(n)的合数必然会被小于等于sqrt(n)的素数去掉,而1要去掉
(2)
g[n][m]=g[n][m-1]-g[n/c[m]][m-1]
//n以内不被前m-1个素数整除的数,那么还要减去被c[m]整除而不被c[1..m-1]整除的
对于
g[n][m]
的计算的优化(很有用,当n在我们预处理的范围maxn中时):
1)若
f[n]<=m
说明n内除了1之外所有数都可以被c[1..m]整除掉(return 1)
2)若
f[n√]<=m
说明只有n内的素数#可能#满足g[n][m],那么要去掉m个素数在加上1(return f[n]+1-m)
任之洲论文如是说:
洲阁筛是“对形式较为一般的积性函数给出一种求和算法”
积性函数:
设n的质因数分解为:
n=Πki=1p[i]c[i]
(即
n=p[1]c[1]×p[2]c[2]×...×p[k]c[k]
)
有积性函数F(n)满足:
·当n为质数时,
F(n)=G(n)
·当n=
pc
时,
F(pc)=T(pc)
·其他情况根据积性函数的积性,
F(n)=Πki=1F(p[i]c[i])
(即
F(n)=F(p[1]c[1])×F(p[2]c[2])×...×F(p[k]c[k])
)
对于Euler函数,
G(p)=p−1,T(pc)=(p−1)p(c−1)
对于莫比乌斯函数,
G(p)=−1,T(pc)=0
抛砖引玉:
有函数
F(n)=Πki=1(p[i]c[i]+d)
求前缀和,利用之前的表示方法,
G(p)=p+d,T(pc)=pc+d
转化1:
根据引理:对于一个在n以内的数x,x最多拥有一个大于
n√
的质因子
那么F(x)可以分两类考虑:
·x没有大于
n√
的质因子
·x有一个大于
n√
的质因子
得到
∑ni=1F(i)=∑x≤n且x没有大于n√的质因子F(x)×(1+∑n√<p≤[nx]且p为质数G(p))
观察得到,后面乘上的系数只与
[nx]
有关,所以不同的系数只有
O(n√)
种,可以根据
[nx]
的取值将F(x)分成
O(n√)
段,每一段对应着一样的系数
于是需要处理的就是两部分:
·
∑n√<p≤[nx]且p为质数G(p)
·
∑x没有大于n√的质因子F(x)
G(p)的计算
设不超过
n√
的质数总共有m个,升序排序为c[1..m]
设g[k][n][m]表示n内与前m个质数互质的所有数的k次幂之和,当m=0时就是自然数幂求和
当i>=1时:
g[k][n][m]=g[k][n][m−1]−c[m]k×g[k][n/c[m]][m−1]
最终得到的g[k][n][m]-1即为[1,n]范围内大于
n√
的质数的k次幂之和
根据两个引理:
·设正整数x,y,a,b,其中
a,b≤x,y=[xa]
那么有
[yb]=[xab]
·对于所有
i≤n√
,
[ni]
的取值有
O(n√)
种
对于所有
i<n√
,
[ni]
的取值也有
O(n√)
种
得到计算g[k][i][j]时,i的状态数只有
O(n√)
种,且这些状态刚好为需要被计算的G(p)之和
朴素实现
朴素的实现这一个递推式需要依次枚举质数p[i],对每一个状态进行计算。
对每一个
[nx]
中有多少个质数需要转移,时间复杂度
O(nlogn)
优化
当c[j+1]>i时,g[k][i][j]=1(因为只有1满足要求)
所以当
c[j]2>i≥c[j]
时,即
l=[ic[j]]<c[j]
时有
g[k][l][j−1]=1
得
g[k][i][j]=g[k][i][j−1]−c[j]k×g[k][i/c[j]][j−1]=g[k][i][j−1]−c[j]k
于是当
c[j]2>i
时的计算可以直接省掉
那么对于每一组
[nx]
只需要转移不超过
[nx]−−−√
的质数,利用积分,可以得到:
O(∫n√0nx√dxlogn)=O(n34logn)
F(x)的计算
由于
[nx]
值相同的F(x)需要乘的系数是一样的,可以直接用
[nx]
来表示状态
同样设不超过
n√
的质数总共有m个,升序排序为c[1..m]
设f[i][j]表示只包含前j种质因子,且
[nx]=i
的F(x)之和,其中f[n][0]=1
类似的,第一维中只有
O(n√)
种状态。
朴素实现
由f[i][j-1]转移过来,那么枚举幂次t,设
l=[ic[j]t]
,那么:
·当t>1时,对
f[l][j]
的贡献为
T(c[j]t)×f[i][j−1]
·当t=1时,对
f[l][j]
的贡献为
G(c[j])×f[i][j−1]
注意,上面看上去是反过来递推的,这是因为,我们的第一维是指
[nx]
复杂度与G(p)的朴素实现类似。
优化
在G(p)的计算中省去了
c[j]2>i
的计算,这里同样考虑相似的优化措施。
当
[nx]
不超过
n√
时有:
1+∑n√<p<[nx]且p为质数G(p)=1
而最后的计算答案的式子为:
∑ni=1F(i)=∑x≤n且x没有大于n√的质因子F(x)×(1+∑n√<p≤[nx]且p为质数G(p))
当
c[j]2>y=[nx]
时,
[yc[j]]<c[j]≤n√
,所以状态y最多只能用一个超过c[j]的质数转移,并且转移后的值的答案的贡献系数一定为1
优化后的策略如下:
·对于一个质数c[i],只考虑
y≥c[i]2
的情况
·设
l=[yc[i]t]
,假如
l<c[i]2
那么这个状态在之后会被忽略,需要现在计算他对答案的贡献,也就是统计
[c[i+1],l]
范围内的G(p)之和
·维护每个状态最后一次转移时的c[i],统计被忽略的那一段G(p)之和
复杂度类似
撒花!!!!!!!!!!
代码
先留个坑先。