1. gcd
int gcd(int a, int b)
{
return b? gcd(b, a%b): a;
}
//O(logmax(a, b)
2. 质数
设n>=2为整数, 若所有满足1<k<n的整数k都不是n的约数,则称n为质数或素数,否则称n为合数。
2.1 唯一分解定理(质因数分解)
其中
p
1
<
p
2
<
.
.
.
<
p
m
为
质
数
,
k
i
为
正
整
数
p_1<p_2<...<p_m为质数,ki为正整数
p1<p2<...<pm为质数,ki为正整数
2.1.1 分解方法
// 暴力方法1
vector<int> factor(int n)
{
vector<int> f;
for(int i=2; i<=n;i++)
{
while(n%i == 0)
{
f.push_back(i);
n /= i;
}
}
if(n>1) f.push_back(n);
return f;
}
//O(n)
//暴力方法2
//依据:如果该数为合数,必定有一个根是小于根号n的
vector<int> factor(int n)
{
vector<int> f;
for(int i=2; i*i<=n; i++)
{
while(n%i == 0)
{
f.push_back(i);
n /= i;
}
}
if(n>1) f.push_back(n);
return f;
}
//O($\sqrt(n)$
//先找质数
vector<int> p;
vector<int> factor(int n)
{
vector<int> f;
for(int i=0;i<p.size();i++)
if(p[i]*p[i]>n)
break;
while(n%p[i]==0){
f.push_back(p[i]);
n /= p[i];
}
if(n>1)
f.push_back(n);
return f;
}
O ( ( n ) l o g ( n ) ) O(\frac{\sqrt{(n)}}{log(n)}) O(log(n)(n))
2.2.筛法
2.2.1 调和级数
设调和级数前n项的和为
f
(
n
)
f(n)
f(n),即
f
(
n
)
=
∑
i
=
1
n
1
i
f(n) = \sum_{i=1}^n \frac{1}{i}
f(n)=i=1∑ni1
可以证明
f
(
n
)
=
O
(
l
o
g
(
n
)
)
f(n) = O(log(n))
f(n)=O(log(n))
筛法一
从2到n,枚举整数i,标记大于i且不大于n的i的倍数。枚举到i时,若i没有被标记过,则i为质数。
复杂度为
O
(
∑
i
=
1
n
)
=
O
(
n
l
o
g
(
n
)
)
O(\sum_{i=1}^{n}) = O(nlog(n))
O(i=1∑n)=O(nlog(n))
bool vis[N+1];
vector<int> p;
void sieve(){
for(int i=0;i<=N;i++)
{
if(!vis[i])
p.push_back(i);
for(int j=i*2;j<=N;j++)
vis[j] = 1;
}
}
筛法二
从2到n枚举整数i,若i是质数,标记大于i且不大于n的i的倍数。枚举到i时,若i没有被标记过,则i为质数。
可以证明复杂度为O(nloglogn)。这种筛法有个不好记的名字。
bool vis[N+1];
vector <int> p;
void sieve(){
for(int i = 2; i <= N; ++i)
if(!vis[i]){
p.push_back(i);
for(int j = i*2; j <= N; j += i)
vis[j] = 1;
}
}
筛法三
欧拉筛
从2到n枚举整数i,再从小到大枚举所有不大于i的最小质因子的质数po,标记ipo。显然,枚举到的po总是ipo的最小质因子,而更大的po均不可能是ipo的最小质因子。同样,枚举到i时,若没有被标记过,则i为质数。
每个合数都只会在其最小的质因子被枚举到时被标记,故复杂度为O(n)。这种筛法称为欧拉筛或线性筛。
3.积性函数
设f(n)为定义在正整数上的函数,如果f(1)=1,且对于任意正整数a,b,只要a和b互质,就有
f ( a b ) = f ( a ) f ( b ) f(ab)=f(a)f(b) f(ab)=f(a)f(b)
则称f(n)为积性函数。
若不要求a和b互质,则称f(n)为积性函数.
计算方法:
一般,求出n的分解式n=
bool vis[N+1];
vector <int> p;
int c[N+1], f[N+1];
void sieve(){
for(int i = 2; i <= N; ++i){
if(!vis[i]){
p.push_back(i);
for(int j = i, k = 1;; ++k)
{
c[j] = j; f[j] = cal(i, k);
if(j > N/i)
break; j *= i;
}
}
for(int j = 0; i*p[j] <= N; ++j)
{
vis[i*p[j]] = 1;
if(i%p[j] == 0)
{
c[i*p[j]] = c[i]*p[j];
f[i*p[j]] = f[i/c[i]]*f[c[i]*p[j]];
break;
}
c[i*p[j]] = p[j];
f[i*p[j]] = f[i]*f[p[j]];
}
}
}