2021-07-19

数学知识

这是我在acwing上yxc的算法基础课上所做的笔记,内容基于课上所讲内容,代码模板都来自于acwing
www.acwing.com

质数

定义:只能被1和自己本身所整除的大于1的自然数

1. 判断素数的方法
bool is_prime(int x)
{
	if(x > 1) return false;
	for(int i=2;i <= x;i++)
	{
		if(x%i==0)return false;
	}
	return true;
}
暴力做法,对于每一个小于x的数都进行判定(时间复杂度O(n))
bool is_prime(int x)
{
	if(x > 1) return false;
	for(int i=2;i <= x/i;i++) 
	{
        if(x%i==0) return false;
	}   
    return true;
}
试除法优化
由于 x可以整除i, 所以x/i也可以被整除,约数的出现是成对出现的。所以我们只要枚举到较小的那一个就行. 时间复杂度为O(√n).
之所以结束条件不选择i <= sqrt(x)和i*i <= x, 每次循环计算sqrt(x)速度过慢, i*i有溢出风险

应用: 快速将一个数分解质因数
    vector<pair<int, int>> divide(int x)
    {
        vector<pair<int, int>> v; // 返回一个{底数, 指数}的数组
        for(int i=2;i <= x/i;i++)
        {
            if(x%i==0)
            {
                int cnt=0;
                while(x%i==0)
                {
                    cnt++;
                    x/=i;
                }
                v.push_back({i, cnt});
            }
        }
        if(x > 1) v.push_back({x, 1}); // 存在特殊情况,需要特判。

        return v;
    }

2. 筛质数
快速求1~n中质数的个数
    int prime(int n)
    {
        int prime[MAX], cnt=0;
        bool st[MAX]
        for(int i=2;i <= n;i++)
        {
            if(!st[i])
            {
                prime[cnt++]=i;
            }
            for(int j=i;j <= n;j+=i)
            {
                    st[j]=true;
            }
        }
    }
暴力做法,时间复杂度O(nlogn)
时间复杂度的计算:外层循环n, 内层对于(1/2+1/3+...+1/n)为调和级数,为log n;
缺点:对于一些数会被其约数中的合数和质数筛一遍(eg:18 会被2,3,6,9,18同时筛一遍)
    int prime(int n)
    {
        int prime[MAX], cnt=0;
        bool st[MAX]
        for(int i=2;i <= n;i++)
        {
            if(!st[i])
            {
                prime[cnt++]=i;
                for(int j=i;j <= n;j+=i)
                {
                    st[j]=true;
                }
            }
        }
        return cnt;
    }
埃式筛法(埃拉托斯特尼筛法),时间复杂度O(nloglogn);
改进:一个数只会被质数所筛去
缺点:还存在重复筛选的问题(eg:6会被2和3所筛去)
    int prime(int n)
    {
        int prime[MAX], cnt=0;
        bool st[MAX]
        for(int i=2;i <= 2;i++)
        {
            if(!st[i])
            {
                prime[cnt++]=i;
            }
            for(int j=0;prime[j] <= n/i;j++) //转换一下就是prime[j]*i <= n; 此时的数已经超过了n,没有了意义。
            {
                st[prime[j]*i]=true; 
                if(i%prime[j]==0) break; // 确保prime[j]*i只会被其最小的质因数所筛去
            }
        }
        return cnt;
    }
线性筛法, 故名思意时间复杂度为O(n)
优点:保证了一个合数只会被其的最小质因数所筛去。

…持续更新

上一篇:HDU分拆素数和


下一篇:【扩欧】Ptynb!!