信奥赛基础:时间复杂度、初等数论

一、分析方法

  • 识别计算机基础操作:赋值、比较、加减乘除
  • 估算基本操作在程序中执行的次数(与数据规模 n n n 相关)
  • 使用大 O O O 法最简表示:
    • 用于描述算法的最坏复杂度(输入数据最坏的情况)
    • 对于同一变量 n n n,保留影响最大的项
    • 适当省略系数

二、复杂度排序

1. 排序

当数据规模 n ≥ 1000 n\ge 1000 n1000 时,下面是运行时间从小到大的排序:

排序表示运行次数(估)
1. O ( 1 ) O(1) O(1) / / /
2. O ( log ⁡ n ) O(\log n) O(logn) 10 10 10
3. O ( n ) O(\sqrt n) O(n ) 31 31 31
4. O ( n ) O(n) O(n) 1000 1000 1000
5. O ( n log ⁡ n ) O(n \log n) O(nlogn) 1 0 4 10^4 104
6. O ( n 2 ) O(n^2) O(n2) 1 0 6 10^6 106
7. O ( 2 n ) O(2^n) O(2n) 1 0 31 10^{31} 1031
8. O ( n ! ) O(n!) O(n!) 4 × 1 0 2567 4\times 10^{2567} 4×102567

2. 注意事项

  1. 在数学中, n 1 x = n x n^{\frac{1}{x}}=\sqrt[x]{n} nx1=xn 。如, n 1 2 = n n^{\frac{1}{2}}=\sqrt{n} n21=n

三、初等数论

1. 数

1.1 列举因数

时间复杂度: O ( n ) O(\sqrt n) O(n )

for(int i=1;i*i<=n;i++)
	if(n%i==0){
		if(i*i==n)factors.push_back(i);
		else{
		    factors.push_back(i);
		    factors.push_back(n/i);
		}
	}

1.2 判断质数

时间复杂度: O ( n ) O(\sqrt n) O(n )

bool isPrime(int n){
	if(n<2)return false;
	for(int i=2;i*i<=n;i++)
		if(n%i==0)
			return false;
	return true;
}

1.3 埃筛

时间复杂度: O ( n log ⁡ log ⁡ n ) O(n\log \log n) O(nloglogn)

  1. 每次外层循环都把 i i i 的倍数筛掉
  2. 循环内只枚举质数的倍数, i i i 的倍数 j j j 的枚举下限 j = i 2 j=i^2 j=i2,打上合数标记
  3. 每次 j j j += i i i
vector<int>f(int n){
	vector<int>primes;//质数数组
	vector<bool>isPrime(n+1,true);//默认都是质数
	isPrime[0]=isPrime[1]=false;//0和1不是质数
	for(int i=2;i*i<=n;i++)
		if(isPrime[i])//是质数
			for(int j=i*i;j<=n;j+=i)
				isPrime[j]=false;//标为合数
	for(int i=1;i<=n;i++)
		if(isPrime[i])
			primes.push_back(i);
	return primes;
}

1.4 线性筛

时间复杂度: O ( n ) O(n) O(n)

  1. 每次外层循环筛掉素数表中部分素数的 i i i
  2. 循环内判断 i i i 是不是质数,是则加入质数表
  3. 枚举素数表中素数 prime[j],筛掉 i*prime[j]
  4. 筛完后若发现 i i iprime[j] 的倍数,退出内层循环
vector<int>f(int n){
	vector<int>primes;
	vector<bool>isPrime(n+1,true);
	isPrime[0]=isPrime[1]=false;
	for(int i=2;i<=n;i++){
		if(isPrime[i])primes.push_back(i);
		for(int j=0;j<primes.size()&&primes[j]*i<=n;j++){
			isPrime[primes[j]*i]=false;
			if(i%primes[j]==0)break;
		}
	}
	return primes;
}

1.5 分解质因数

时间复杂度: O ( n log ⁡ n ) O(\sqrt{n} \log n) O(n logn)
本质是重复以下过程:

  1. 找到 n n n 的最小值因数 i i i
  2. n n n 内含有的 i i i 都除净
  3. 此时 n n n n ≠ 1 n\ne1 n=1)的最小质因数 > i >i >i
vector<int>primeFac(int n){
    vector<int>factors;
    for(int i=2;i*i<=n;i++)
    	while(n%i==0){
    		factors.push_back(i);
    		n/=i;
    	}
    if(n!=1)factors.push_back(n);
    return factors;
}

2. 辗转相除法(欧几里得算法)

时间复杂度: O ( log ⁡ n ) O(\log n) O(logn)

//循环写法
while(b){
    int r=a%b;
    a=b;
    b=r;
}
//递归写法
return (b==0)?a:gcd(b,a%b);

3. 理论

唯一分解定理:每个合数都可以唯一分解为一系列质数的乘积。

因子数量公式:若 a = p 1 x 1 p 2 x 2 ⋯ p n x n a=p_1^{x_1}p_2^{x_2}\cdots p_n^{x_n} a=p1x1p2x2pnxn a a a 有因子 ( x 1 + 1 ) ( x 2 + 1 ) ⋯ ( x n + 1 ) (x1+1)(x2+1)\cdots (x_n+1) (x1+1)(x2+1)(xn+1)

若干个数最小公倍数是每个质因子出现的最高次幂的乘积。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值