码迷,mamicode.com
首页 > 其他好文 > 详细

线性筛合集

时间:2019-02-09 10:24:06      阅读:166      评论:0      收藏:0      [点我收藏+]

标签:putc   define   mod   乘法   clu   约数和   names   线性   个数   

迟到的线性筛合集。

1.线性筛质数。
这个不讲了大家都会。不过他是下面的基础。注意每个数都是被最小质因子筛去的。

2.线性筛逆元。
这个有两种做法。第一种是质数直接用费马小定理,然后根据逆元是完全积性函数直接乘起来。
第二种直接线性递推。设\(p = ki + b\),则有\(ki + b \equiv 0 (mod\ p),b = p\ \%\ i,k = \lfloor\frac{p}{i}\rfloor\)
\(b \equiv -ki (mod\ p)\)两边同乘\(inv_b,inv_i\),有:\(inv_i \equiv -k * inv_b (mod\ p)\)
得到:\(inv[i] = (p - \lfloor\frac{p}{i}\rfloor) * inv[p\%i]\ \%\ p\) 边界为\(inv[0] = inv[1] = 1\),线性递推即可。

3.线性求欧拉函数。
欧拉函数是积性函数,不是完全积性函数。
对于质数,\(\varphi(x) = x - 1\).
对于合数,如果对于现在被筛去的数,当前最小质因子是一个新的质因子,那么\(\varphi(i * p[j]) = \varphi(i) * \varphi(p[j])\)
否则\(\varphi(i * p[j]) = \varphi(i) * p[j]\)

上面一项是因为两数互质,可以用积性函数的性质。
下面一项的证明:(可能很麻烦……反正是从别人那里看来的,不知道有没有更优秀的证明)
对于i,\([1,i)\)中与i不互质的数有\(i - \varphi(i)\)个。
对于任意数n,如果其与i互质,那么n+i与i互质。如果其与i不互质,那么n+i与i不互质。前者可以用反证法,后者是显然的。
可以推论得到,对于数i * p,其中与i不互质的数个数为\(i * p - p * \varphi(i)\)
那么显然有\(i * p - p * \varphi(i) = i * p - \varphi(i * p)\),所以\(p * \varphi(i) = \varphi(i * p)\)

4.线性求莫比乌斯函数。
莫比乌斯函数也是积性函数。根据其定义:
\(\mu(i) = 1\ (i = 1)\)
\(\mu(i) = (-1)^k\ (i = p_1p_2…p_k)\)
\(\mu(i) = 0\ (其余情况)\)
我们就可以得到其线性求法。对于质数,显然有\(mu(i) = -1\)
对于合数,如果正在被筛的数已经含有当前的最小素因子,那么说明这个正在被筛的数含有平方因子,所以\(\mu(i) = 0\)
否则根据定义\(\mu(i * p[j]) = \mu(i) * \mu(p[j])\),即\(\mu(i*p[j]) = -\mu(i)\)

5.线性求约数个数和约数和。
这个用到唯一分解定理的性质。
任意一个数n可以被唯一分解为若干个质数的若干次幂的乘积,即\(n = p_1^{a_1}p_2^{a_2}…p_k^{a_k}\)
\(d(i)\)为约数个数,\(ds(i)\)为约数和。
则有\(d(n) = \prod_{i=1}^{k}(a_i + 1)\),这个很显然,就是每个质数取0~\(a_k\)次幂中的一个,乘法原理。
\(ds(n) = (1 + p_1 + p_1^2 + … + p_1^{a_1}) * (1 + p_2 + p_2^2 + … + p_2 ^ {a_2}) * … *(1 + p_k + p_k^2 + … + p_k^{a_k})\),也就是\(ds(n) = \prod_{i=1}^k\sum_{j=0}^{a_i}p_i^j\)(这个似乎有点不利于理解??)

我们先说求约数个数。这里我们需要令\(num[i]\)表示i的最小素因子在i中的出现次数。
对于质数,有\(d[i] = 2,num[i] = 1\)
对于合数,那么如果这个数没有出现过,则很明显\(d[i * p[j]] = d[i] * d[p[j]],num[i * p[j]] = 1\)
否则这个数出现过,那么我们需要先除以最小素因子出现的次数+1,再乘以这个次数+2,并更新此值,也即是\(d[i*p[j]] = d[i] / (num[i] + 1) * (num[i] + 2),num[i*p[j]] = num[i] + 1\)

约数和与之是相似的。我们令\(dg(i)\)表示i的最小素因子的等比数列的和(就先这么叫吧??)
质数显然有\(ds[i] = dg[i] = i + 1\)
合数的话,如果这个数以前没出现过,那么\(ds[i*p[j]] = ds[i] * ds[p[j]]\)(可以看出这俩都是积性函数)\(dg[i*p[j]] = p[j]+1\)
否则和上一个一样,我们需要先除以这个等比数列,再乘上这个等比数列乘以当前质数+1.即\(ds[i*p[j]] = ds[i] / dg[i] * (dg[i] * p[j] + 1),dg[i*p[j]] = dg[i] * p[j] + 1\)

然后就完事啦。
(代码可能有误,未经测试)

#include<bits/stdc++.h>
#define rep(i,a,n) for(register int i = a;i <= n;i++)
#define per(i,n,a) for(register int i = n;i >= a;i--)
#define enter putchar(‘\n‘)
#define pr pair<int,int>
#define mp make_pair
#define fi first
#define sc second
using namespace std;
typedef long long ll;
const int M = 100005;
const int N = 10000005;
const int mod = 998244353;

int read()
{
   int ans = 0,op = 1;char ch = getchar();
   while(ch < ‘0‘ || ch > ‘9‘) {if(ch == ‘-‘) op = -1;ch = getchar();}
   while(ch >=‘0‘ && ch <= ‘9‘) ans = ans * 10 + ch - ‘0‘,ch = getchar();
   return ans * op;
}

int p[M],phi[M],mu[M],num[M],d[M],ds[M],dg[M],inv[M],tot;
bool np[M];

void euler()
{
   np[1] = 1,inv[0] = inv[1] = 1,mu[1] = 1,d[1] = 1,ds[1] = 1;
   rep(i,2,M-2)
   {
      inv[i] = (mod - mod / i) * inv[mod % i] % mod;
      if(!np[i]) p[++tot] = i,phi[i] = i-1,mu[i] = -1,d[i] = 2,num[i] = 1,ds[i] = dg[i] = i + 1;
      for(int j = 1,k = i * p[j];k <= M-2;j++)
      {
     np[k] = 1;
     if(!(i % p[j]))
     {
        phi[k] = phi[i] * p[j];
        d[k] = d[i] / (num[i] + 1) * (num[i] + 2),num[k] = num[i] + 1;
        ds[k] = ds[i] / dg[i] * (dg[i] * p[j] + 1),dg[k] = dg[i] * p[j] + 1;
     }
     phi[k] = phi[i] * phi[p[j]];
     d[k] = d[i] * d[p[j]],num[k] = 1;
     ds[k] = ds[i] * ds[p[j]],dg[k] = p[j] + 1;
      }
   }
}

int main()
{
   euler();
   return 0;
}

线性筛合集

标签:putc   define   mod   乘法   clu   约数和   names   线性   个数   

原文地址:https://www.cnblogs.com/captain1/p/10357061.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!