前言:
因为我不会州阁筛,所以就只有学习一个他的一个相对简单的但是功能大致相同的筛法:Min_25 筛。
首先,其时间复杂度是
n
3
4
ln
n
\frac{n^{\frac{3}{4}} }{\ln n}
lnnn43的。其功能是求出某个积性函数
f
(
x
)
f(x)
f(x)的前缀和,
并且需要满足如下几个条件:
{
1.
f
(
p
)
是
一
个
多
项
式
(
Let p be a prime
)
2.
f
(
p
c
)
容
易
被
算
出
\begin{cases} 1.f(p) 是一个多项式(\text{Let p be a prime})\\ 2.f(p^c) 容易被算出\\ \end{cases}
{1.f(p)是一个多项式(Let p be a prime)2.f(pc)容易被算出
做法
先规定一些符号以及一些定义:
p
i
p_i
pi表示第
i
i
i个质数,比如
p
1
=
2
,
p
2
=
3
,
p
3
=
5...
p_1=2,p_2=3,p_3=5...
p1=2,p2=3,p3=5...
首先考虑如下函数:
π
k
(
n
)
=
∑
i
=
1
n
i
k
[
i is a prime
]
\pi_k(n) = \sum_{i=1}^{n} i^k[\text{i is a prime}]
πk(n)=i=1∑nik[i is a prime]
那么考虑如何求
π
k
(
n
)
\pi_k{(n)}
πk(n)。定义一个新的函数
π
k
,
j
(
n
)
=
∑
i
=
1
n
i
k
[
i is a prime or i’s minimal prime factor
≥
p
j
]
\pi_{k,j}(n)=\sum_{i=1}^{n} i^k[\text{i is a prime or i's minimal prime factor} \geq p_j]
πk,j(n)=i=1∑nik[i is a prime or i’s minimal prime factor≥pj]首先,我们不妨一开始把所有合数都看成质数,那么此时
π
k
,
0
(
n
)
=
(
∑
i
=
1
n
i
k
)
−
1
\pi_{k,0}(n) = (\sum_{i=1}^{n} i^k) - 1
πk,0(n)=(∑i=1nik)−1,之所以减一是因为一既不是合数也不是质数。
那么现在应该要去掉重复的部分,考虑如何去掉,我们枚举某个合数的最小质因数
p
i
p_i
pi,然后此时有
p
i
k
×
π
k
,
j
−
1
(
⌊
n
p
i
⌋
)
p_i^k \times \pi_{k,j-1}(\lfloor \frac{n}{p_i} \rfloor)
pik×πk,j−1(⌊pin⌋)的贡献,但是注意到这会算重,因为剩下的中有可能有最小质因数比
p
i
p_i
pi还小的数,是哪一部分呢?明显就是前
i
−
1
i-1
i−1小的质数,所以此时应当减去的是:
p
i
k
×
(
π
k
,
j
−
1
(
⌊
n
p
i
⌋
)
−
π
k
,
j
−
1
(
p
i
−
1
)
)
p_i^k \times (\pi_{k,j-1}(\lfloor \frac{n}{p_i} \rfloor) - \pi_{k,j-1}(p_i-1))
pik×(πk,j−1(⌊pin⌋)−πk,j−1(pi−1))。
那么既然都可以枚举
p
i
p_i
pi了,那么
π
k
,
0
(
p
i
−
1
)
\pi_{k,0}(p_i-1)
πk,0(pi−1)就可以直接预处理了。
然后我们注意到,这个
⌊
n
p
i
⌋
\lfloor \frac{n}{p_i} \rfloor
⌊pin⌋只有
n
\sqrt{n}
n种,所以可以离散化掉。然后考虑更新顺序,我们可以看到,大的质数要在小的质数之后被筛掉,所以直接
for
\text{for}
for一遍把质数从小到大就行了。代码如下(这里以
π
0
\pi_0
π0为例):
int val , pi0 , vcnt;
//离散化
for (ll i = 1;i <= n; i++) {
val[++vcnt] = n / i;
pi0[vcnt] = val[vcnt] - 1;
if (val[vcnt] < N) id1[val[vcnt]] = vcnt;
else id2[n / val[vcnt]] = vcnt;//离散化的数组
i = n / (n / i);
}
//从这开始筛
for (int j = 1;j <= pcnt; j++)
for (int i = 1;i <= vcnt && p[j] * p[j] <= val[i]; i++) {
int k = (val[i] / p[j]) < N ? id1[val[i] / p[j]] : id2[n / (val[i] / p[j] ) ];
pi0[i] -= pi0[k] - ( j - 1 );
}
可以发现,实现很简单。复杂度?就是 n 3 4 ln n \frac{n^{\frac{3}{4}} }{\ln n} lnnn43,然而我不会证明。
下面继续,我们设 F ( x , j ) F(x,j) F(x,j)表示 ∑ i = 1 x f ( i ) [ i is a prime or i’s minimal prime factor > p j ] \sum_{i=1}^{x} f(i)[\text{i is a prime or i's minimal prime factor >} p_j] i=1∑xf(i)[i is a prime or i’s minimal prime factor >pj],那么首先 F ( x , j ) F(x,j) F(x,j)应当有所有质数的 f f f值的和,这个之前已经处理过了。
然后还是看合数,同理枚举最小的质因数
p
i
(
i
≥
j
)
p_i(i \geq j)
pi(i≥j),枚举其次幂
e
e
e,满足
p
i
e
≤
x
p_i ^{e} \leq x
pie≤x,那么答案便可以加上
F
(
x
p
i
e
,
i
+
1
)
×
f
(
p
i
e
)
F( \frac{x}{p_i^e} , i + 1) \times f(p_i^e)
F(piex,i+1)×f(pie),然而值得注意的是,无论
j
j
j是几,
F
F
F中都不包含
1
1
1,所以我们还要另外加上
f
(
p
i
e
)
f(p_i^e)
f(pie)。
这部分很好理解,相当于就是暴力枚举约数,然后递归下去。
代码如下:
ll F(ll x ,int j){
if (x <= 1 || pri[j] > x) return 0;
int k = x < N ? id1[x] : id2[n / x];
ll ans = //sum of primes;
for (int i = j;i <= pcnt && pri[i] * pri[i] <= x; i++ ) {
ll t = pri[i];
for (int e = 1; t <= x ; e++ , t = t * pri[i] ){
ans += F(x / t1 , i + 1) * f(t) + f(t);
}
ans -= f(pri[i]);
}
return ans;
}
最后,我们注意到
F
(
n
,
1
)
+
f
(
1
)
F(n,1)+f(1)
F(n,1)+f(1)就是答案,因为
1
1
1没有质因子,所以
F
(
n
,
1
)
F(n,1)
F(n,1)算不到他。
然后就完了。
当然,我们也就注意到了这个筛可以算许多东西,比如算
π
(
x
)
\pi(x)
π(x)这种。
例如:
Loj 6028(6027)
求
[
1
,
n
]
[1,n]
[1,n]中模
m
m
m为
p
p
p的质数个数。
#Solution
注意这个初始,就只把
t
m
+
p
tm+p
tm+p的数算起来,然后讨论一下就完了。就是说,如果你用质数
p
k
p_k
pk来更新
p
i
(
i
)
pi(i)
pi(i),然后
p
k
=
=
b
(
m
o
d
m
)
p_k==b(\mod m)
pk==b(modm),然后你就得用
p
k
×
i
n
v
(
b
)
p_k \times inv(b)
pk×inv(b)来更新一下。