基础数论

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 &lt; p 2 &lt; . . . &lt; p m 为 质 数 , k i 为 正 整 数 p_1&lt;p_2&lt;...&lt;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=1ni1
可以证明
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=1n)=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) fab=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]];
} 
}   
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值