前言:好多学ACM的人都在问我数论的知识(其实我本人分不清数学和数论有什么区别,反正以后有关数学的知识我都扔进数论分类里面好了)

于是我就准备写一个长篇集,把我知道的数论知识和ACM模板都发上来(而且一旦模板有更新,我就直接在博客上改了,所以记得常来看看(。・ω・))

废话说完了,直接进入正题ヾ(=^▽^=)ノ

素数,又叫质数,定义是除了1和它本身以外不再有其他的因数

我们通过这个定义,可以写如下程序判断一个数是不是质数

 bool prime(int x){//判断x是不是质数,是返回true,不是返回false
if(x <= ) return false;
for(int i = ; i < x; i ++){
if(x % i == ) return false;
}
return true;
}

这个程序的时间复杂度是O(n),有没有更快的方法,当然

看这个

 bool prime(int x){//判断x是不是质数,是返回true,不是返回false
if(x <= ) return false;
for(int i = ; i <= sqrt(x + 0.5); i ++){//0.5是防止根号的精度误差
if(x % i == ) return false;
}
return true;
}
//另一种方法,不需要根号
bool prime(int x){//判断x是不是质数,是返回true,不是返回false
if(x <= ) return false;
for(int i = ; i * i <= x; i ++){//用乘法避免根号的精度误差
if(x % i == ) return false;
}
return true;
}
//根据题目不同,如果i*i会爆int,记得开longlong

这个复杂度是O(√n),速度快多了(#°Д°)

根据题目不同,有可能你需要先预处理出1~N这N个数是否是素数

如果用刚刚的方法,复杂度就是O(n√n)

 #include<cstdio>
const int N = + ;
bool prime[N];
bool is_prime(int x){
if(x <= ) return false;
for(int i = ; i * i <= x; i ++){
if(x % i == ) return false;
}
return true;
}
void init(){
for(int i = ; i < N; i ++){
prime[i] = is_prime(i);
}
}
int main(){
init();
}

如果n大一点,就太慢了(。・ω・)ノ゙

介绍一种新方法,埃筛

埃筛--------------埃拉托斯特尼筛法,或者叫埃氏筛法

原理:如果找到一个质数,那么这个质数的倍数都不是质数

比如2是质数,那么4,6,8,10,12...都不是质数

然后看3是质数,那么6,9,12,15,18,21...都不是质数

然后看4,4已经被2标记为合数了,所以跳过

然后看5......这样一直筛下去

 #include<cstdio>
const int N = + ;
bool prime[N];
void init(){
for(int i = ; i < N; i ++) prime[i] = true;//先全部初始化为质数
for(int i = ; i < N; i ++){
if(prime[i]){//如果i是质数
for(int j = *i; j < N; j += i){//从i的两倍开始的所有倍数
prime[j] = false;
}
}
}
}
int main(){
init();
}

因为一些数字,比如6既被2的for循环经过又被3的for循环经过,所以复杂度不是O(n)

这个复杂度经过专业人士检验,复杂度O(nloglogn)(学过高数的小朋友可以自己证明≖‿≖✧当然也可以去百度)

知道原理后,我们再稍微优化一下就更快了

 #include<cstdio>
const int N = + ;
bool prime[N];
void init(){
for(int i = ; i < N; i ++) prime[i] = true;
for(int i = ; i*i < N; i ++){//判断改成i*i<N
if(prime[i]){
for(int j = i*i; j < N; j += i){//从i*i开始就可以了
prime[j] = false;
}
}
}
}
int main(){
init();
}

好戏都是要留到最后的≖‿≖✧确实还有O(n)的做法

这个算法名字叫线筛

 #include<cstdio>
const int N = + ;
bool prime[N];//prime[i]表示i是不是质数
int p[N], tot;//p[N]用来存质数
void init(){
for(int i = ; i < N; i ++) prime[i] = true;//初始化为质数
for(int i = ; i < N; i++){
if(prime[i]) p[tot ++] = i;//把质数存起来
for(int j = ; j < tot && i * p[j] < N; j++){
prime[i * p[j]] = false;
if(i % p[j] == ) break;//保证每个合数被它最小的质因数筛去
}
}
}
int main(){
init();
}

这个方法可以保证每个合数都被它最小的质因数筛去

所以一个数只会经过一次

时间复杂度为O(n)

其实loglogn非常小,把埃筛看成线性也无妨,毕竟它比线筛好写

基于埃筛的原理,我们可以用它干很多事

比如预处理每个数的所有质因数

 #include<cstdio>
#include<vector>
using namespace std;
const int N = + ;
vector<int > prime_factor[N];
void init(){
for(int i = ; i < N; i ++){
if(prime_factor[i].size() == ){//如果i是质数
for(int j = i; j < N; j += i){
prime_factor[j].push_back(i);
}
}
}
}
int main(){
init();
}

比如预处理每个数的所有因数

 #include<cstdio>
#include<vector>
using namespace std;
const int N = + ;
vector<int > factor[N];
void init(){
for(int i = ; i < N; i ++){
for(int j = i; j < N; j += i){
factor[j].push_back(i);
}
}
}
int main(){
init();
}

比如预处理每个数的质因数分解

 #include<cstdio>
#include<vector>
using namespace std;
const int N = + ;
vector<int > prime_factor[N];
void init(){
int temp;
for(int i = ; i < N; i ++){
if(prime_factor[i].size() == ){
for(int j = i; j < N; j += i){
temp = j;
while(temp % i == ){
prime_factor[j].push_back(i);
temp /= i;
}
}
}
}
}
int main(){
init();
}

世界之大无奇不有(。-`ω´-)数论是个可怕的东西

ACM数论之旅1---素数(万事开头难(>_<))的更多相关文章

  1. acm数论之旅--欧拉函数的证明

    随笔 - 20  文章 - 0  评论 - 73 ACM数论之旅7---欧拉函数的证明及代码实现(我会证明都是骗人的╮( ̄▽ ̄)╭) https://blog.csdn.net/chen_ze_hua ...

  2. acm数论之旅--数论四大定理

    ACM数论之旅5---数论四大定理(你怕不怕(☆゚∀゚)老实告诉我)   (本篇无证明,想要证明的去找度娘)o(*≧▽≦)ツ ----------数论四大定理--------- 数论四大定理: 1.威 ...

  3. acm数论之旅--中国剩余定理

    ACM数论之旅9---中国剩余定理(CRT)(壮哉我大中华╰(*°▽°*)╯)   中国剩余定理,又名孙子定理o(*≧▽≦)ツ 能求解什么问题呢? 问题: 一堆物品 3个3个分剩2个 5个5个分剩3个 ...

  4. acm数论之旅--组合数(转载)

    随笔 - 20  文章 - 0  评论 - 73 ACM数论之旅8---组合数(组合大法好(,,• ₃ •,,) )  补充:全错排公式:https://blog.csdn.net/Carey_Lu/ ...

  5. acm数论之旅(转载) -- 逆元

    ACM数论之旅6---数论倒数,又称逆元(我整个人都倒了( ̄﹏ ̄))   数论倒数,又称逆元(因为我说习惯逆元了,下面我都说逆元) 数论中的倒数是有特别的意义滴 你以为a的倒数在数论中还是1/a吗 ( ...

  6. 万事开头难——Cocos2d-x学习历程(一)

    万事开头难,不知该从哪里开始,不过既然要学习一样新东西,那就从了解它开始吧... Cocos2d-x是一个通用平面游戏引擎,基于一个同样十分著名的游戏引擎Cocos2d-iPhone设计,Cocos2 ...

  7. 一个想法照进现实-《IT连》创业项目:万事开头难

    前言: 之前是一个想法,现在已经进入创业阶段,所以这个系列的标题,改了. 众筹的事在今天也停止了. 7-9号会在深圳龙岗布吉参加一个风投对接的活动,今晚(6号)会出发. 因为:在深圳会呆几天,而且这个 ...

  8. 万事开头难 && 实践出真知

    实践出真知,真是千古不变的真理. 前几天在顺手做一个万年历项目,实现了用TFT屏显示实时时间,日期,温度,和按键设置时间,能在特定时间显示特定的话语在显示屏上面.其实这个项目现在想想还是挺简单的.我的 ...

  9. 万事开头难,用HTML写的第一个界面,收获颇多

        很开心跟了叶老师学习和做项目,基础不好,前期他会帮你安排好学习路线和计划.前期没有项目做,叶老师先让我先学习jQuery,给我推荐了一些网站,叫我一边学习,一边写博客.其实很早就有想写博客的想 ...

随机推荐

  1. 4821: [Sdoi2017]相关分析

    4821: [Sdoi2017]相关分析 链接 分析: 大力拆式子,化简,然后线段树.注意精度问题与爆longlong问题. 代码: #include<cstdio> #include&l ...

  2. P3674 小清新人渣的本愿

    P3674 小清新人渣的本愿 一道妙不可言的题啊,,, 一看就知道是个莫队 考虑求答案 1号操作就是个大bitset,动态维护当前的bitset \(S\),把能取哪些值都搞出来,只要\(S\ and ...

  3. vue复习(一)

    一.认识Vue 定义:一个构建数据驱动的Web界面的渐进式框架 优点: 1.可以完全通过客户端浏览器渲染页面,服务器端只提供数据 2.方面构建单页面应用程序(SPA) 二.引入Vue <!DOC ...

  4. Python之函数的递归、匿名函数、内置函数

    一.函数的递归 ''' 1 什么是函数递归 函数递归调用(是一种特殊的嵌套调用):在调用一个函数的过程中,又直接或间接地调用了该函数本身 递归必须要有两个明确的阶段: 递推:一层一层递归调用下去,强调 ...

  5. Flutter - 创建横跨所有页面的侧滑菜单

    前一篇博客讲到了如何创建侧滑菜单,但是再实际使用过程中,会发现,这个策划菜单只能在首页侧滑出来. 当导航到其他页面后,侧滑就不管用了.这也有点不符合良好的用户体验设计.Google Play就是很好的 ...

  6. 【UGUI】 (三)------- 背包系统(上)之简易单页背包系统及检索功能的实现

    背包系统,无论是游戏还是应用,都是常常见到的功能,其作用及重要性不用我多说,玩过游戏的朋友都应该明白. 在Unity中实现一个简易的背包系统其实并不是太过复杂的事.本文要实现的是一个带检索功能的背包系 ...

  7. RabbitMQ入门:Hello RabbitMQ 代码实例

    在之前的一篇博客RabbitMQ入门:认识并安装RabbitMQ(以Windows系统为例)中,我们安装了RabbitMQ并且对其也有的初步的认识,今天就来写个入门小例子来加深概念理解并了解代码怎么实 ...

  8. Hyperledger Fabric MSP Identity Validity Rules——MSP身份验证规则

    MSP Identity Validity Rules——MSP身份验证规则 正如Hyperledger Fabric Membership Service Providers (MSP)——成员服务 ...

  9. socket 编程 : shutdown vs close

    TCP/IP 四次挥手 首先作者先描述一下TCP/IP 协议中四次挥手的过程,如果对此已经熟悉的读者可以跳过本节. 四次挥手 这是一个很经典的示例图,众所周知tcp socket 在一个生命周期中有很 ...

  10. 从零开始的Python学习Episode 23——进程

    ---恢复内容开始--- 进程 由于GIL的存在,python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在python中大部分情况需要使用多进程.Python提供了非常好用 ...