acwing算法基础课笔记4(一)

第四章 数学知识——数论

1、质数

判断一个数是质数:当这个数大于1,且只包含1和它本身这两个约数。

1)质数的判定——试除法:i从2到sqrt (n)就可判断,但是不推荐直接用sqrt,因为它很慢,也不推荐i*i<=n,因为可能会有溢出风险。 

#include<iostream>
#include<algorithm>

using namespace std;

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

int main()
{
	int n;
	cin>>n;
	while(n--)
	{
		int x;
		cin>>x;
		if(isprime(x)) puts("Yes");
		else puts("No");
	}
	return 0;
}

2)分解质因数——短除法

#include<iostream>
#include<algorithm>

using namespace std;

void divide(int n)
{
	for(int i=2;i<=n/i;i++)
	{
		if(n%i == 0)
		{
			int s=0;
			while(n%i==0)
			{
				n/=i;
				s++;
			}
			cout<<i<<" "<<s<<endl;
		}
	}
	if(n>1)
	cout<<n<<" 1"<<endl;
	puts("");
}

int main()
{
	int n;
	cin>>n;
	while(n--)
	{
		int x;
		cin>>x;
		divide(x);
	}
	return 0;
}

3)筛质数

朴素:

#include<iostream>
#include<algorithm>

using namespace std;

const int N=1e6+10;

int prime[N], cnt;
bool st[N];

int cntprime(int n)
{
	for(int i=2;i<=n;i++)
	{
		if(!st[i])
		{
			prime[cnt++] = i;
		}
		for(int j=i+i;j<=n;j+=i) st[j] = true;
	}
	return cnt;
}

int main()
{
	int n;
	cin>>n;
	cout<<cntprime(n)<<endl;
	return 0;
}

时间复杂度计算: O(nlnn)

优化:埃式筛,只需要把质数的倍数晒去即可,因为质数的倍数是合数。

int cntprime(int n)
{
	for(int i=2;i<=n;i++)
	{
		if(!st[i])
		{
			prime[cnt++] = i;
			for(int j=i+i;j<=n;j+=i) st[j] = true;
		}
	}
	return cnt;
}

时间复杂度优化到 约等于o(n)实际上是O(nloglogn)

线性筛:合数一定会被筛掉,核心思路:每个数n只会被它的最小质因子筛掉。因为合数一定存在最小质因子

int cntprime(int n)
{
	for(int i=2;i<=n;i++)
	{
		if(!st[i]) prime[cnt++] = i;
		for(int j=0;prime[j]<=n/i;j++)
		{
			st[prime[j]*i] = true;
			if(i%prime[j] == 0) break;//prime[j]一定是i的最小质因子
		}
	}
	return cnt;
}

n小时与埃式筛相近,n大时比埃式筛快很多 

2、约数

1)求约数——试除法,约数也成对出现,如果当前数不是n的开根号,就把i和n/i都加入变长数组res,复杂度是根号n。

#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

vector<int> getdivision(int n)
{
	vector<int> res;
	for(int i=1;i<=n/i;i++)
	{
		if(n%i == 0)
		{
			res.push_back(i);
			if(i*i!=n) res.push_back(n/i);
		}
	}
	sort(res.begin(), res.end());
	return res;
} 

int main()
{
	int n;
	cin>>n;
	while(n--)
	{
		int x;
		cin>>x;
		vector<int> res=getdivision(x);
		for(auto t:res) cout<<t<<" ";
		cout<<endl;
	}
	return 0;
}

2)求约数的个数,每个数n可以看成p1的a1次方乘上p2的a2次方......,所以约数个数就是(a1+1)*(a2+1)...... ,因为第一项里面有p1的0次方,1次方,一直到a1次方。eg:99=3的平方乘以11.约数就位6个,分别是1x1=1,1x11=11,3x1=3,3x11=33,9x1=9,9x11=99;这六个

 

#include<iostream>
#include<algorithm>
#include<unordered_map>

using namespace std;
unordered_map<int, int> primes;

const int mod=1e9+7;

int main()
{
	int n;
	cin>>n;
	while(n--)
	{
		int x;
		cin>>x;
		for(int i=2;i<=x/i;i++)
		{
			while(x%i==0)
			{
				x/=i;
				primes[i]++;
			}
		}
		if(x>1) primes[x]++;		
	}
	long long int res=1;
	for(auto primei:primes) res=res *(primei.second+1) % mod;
	cout<<res<<endl;
	return 0;
}

3)约数之和

思路上图图解

#include<iostream>
#include<algorithm>
#include<unordered_map>

using namespace std;
unordered_map<int, int> primes;

const int mod=1e9+7;

int main()
{
	int n;
	cin>>n;
	while(n--)
	{
		int x;
		cin>>x;
		for(int i=2;i<=x/i;i++)
		{
			while(x%i==0)
			{
				x/=i;
				primes[i]++;
			}
		}
		if(x>1) primes[x]++;		
	}
	long long int res=1;
	for(auto primei:primes)
	{
		int p = primei.first, a = primei.second;
		long long int t = 1;
		while(a--) 
		{
			t = (p * t + 1) % mod;
		}
		res = res * t % mod;
	}
	cout<<res<<endl;
	return 0;
}

4)欧几里得算法——辗转相除法

a,b的最大公约数等于b和a mod b的最大公约数,只需要特判 b = 0的情况就好了。

#include<iostream>

using namespace std;

int gcd(int a, int b)
{
	return b ? gcd(b, a%b) : a;
}

int main()
{
	int n;
	cin>>n;
	while(n--)
	{
		int a, b;
		cin>>a>>b;
		cout<<gcd(a, b)<<endl;
	}
	return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值