Min_25筛

前言:

因为我不会州阁筛,所以就只有学习一个他的一个相对简单的但是功能大致相同的筛法: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=1nik[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=1nik[i is a prime or i’s minimal prime factorpj]首先,我们不妨一开始把所有合数都看成质数,那么此时 π 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,j1(pin)的贡献,但是注意到这会算重,因为剩下的中有可能有最小质因数比 p i p_i pi还小的数,是哪一部分呢?明显就是前 i − 1 i-1 i1小的质数,所以此时应当减去的是: 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,j1(pin)πk,j1(pi1))
那么既然都可以枚举 p i p_i pi了,那么 π k , 0 ( p i − 1 ) \pi_{k,0}(p_i-1) πk,0(pi1)就可以直接预处理了。
然后我们注意到,这个 ⌊ 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=1xf(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(ij),枚举其次幂 e e e,满足 p i e ≤ x p_i ^{e} \leq x piex,那么答案便可以加上 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)来更新一下。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值