【缄*默】 #数论专题# 数论知识点全面总结(更新ing)

数论中最重要的函数:欧拉函数莫比乌斯函数


目录

【一. 整除与约数】

1.整除的基本概念

2.取整除法

(1)取整除法的概念和应用

(2)取整除法求和

3.因子和约数

(1)基础概念

(2)求N的正约数集合——试除法

(3)试除法的推论

(4)求1~N每个数的正约数集合——倍数法

(5)倍数法的推论

【例题】洛谷 p1403 约数研究

【例题】 bzoj 1053 Antiprime数

4. 最大公约数与最小公倍数

(1)欧几里得算法:求最大公约数

【练习】noip 2009 Hankson的趣味题

(2)二进制算法:求最大公约数

【练习】高精度版最大公约数

(3)互质的概念与性质

(4)最小公倍数

(5)扩展欧几里得算法

【例题】洛谷 p2520 向量

【二. 素数】

(1)基本概念和算法

(2)质数筛法

1.普通筛法

2.埃式筛法

3.欧拉筛法(线性筛法)

(3)唯一分解定理

【三. 同余系与剩余系】

1. 同余的概念和性质

2.1 剩余系与剩余定理

2.2 中国剩余定理(CRT)

3. 乘法逆元

4. 费马小定理

5. 欧拉定理

6. 欧拉函数

7. 积性函数的性质和应用


【一. 整除与约数】

1.整除的基本概念

2.取整除法

(1)取整除法的概念和应用

 

(2)取整除法求和

怎么计算sum{ [n/i] }?(1<=i<=n) (n<=10^13)

n太大,硬算肯定不行,我们先观察一个例子,看能否得出一些结论。

当n=20时,和式展开 20+10+6+5+4+3+2+2+2+2+1+1+1+1+1+1+1+1+1+1

注意到后面相同的数太多,不妨化简下:

20+10+6+5+1*(20-10)+2*(10-6)+3*(6-5)+4*(5-4)

=(20+10+6+5)+(20+10+6+5)-4*4

=2(20+10+6+5)-4*4

这样,复杂度就从O(n)降为O(√n)了。

程序实现(求根号n之前的所有n/i,再根据公式得出答案)

ll ans(ll n){
    ll anss = 0, nn = sqrt(n) ;
    for (ll i = 1; i <= nn; i++) anss += n / i;
    return (anss << 1) - nn * nn;
}

 

3.因子和约数

(1)基础概念

  • 平凡因子:1和自身。
  • 若p是质数,则p没有非平凡因子。
  • 若p没有非平凡因子,则p是质数。

(2)求N的正约数集合——试除法

约数总是成对出现的。只需要扫描因子d=1~√n。

int factor[1600],m=0;
for(int i=1;i*i<=n;i++){
    if(n%i==0){
        factor[++m]=i;
        if(i!=n/i) factor[++m]=n/i;
    }
}
for(int i=1;i<=m;i++) 
    cout<<factor[i]<<endl;

(3)试除法的推论

一个整数N的约数个数上界,为2√N。

(4)求1~N每个数的正约数集合——倍数法

vector<int>factor[500010];
for(int i=1;i<=n;i++)
    for(int j=1;j<=n/i;j++)
        factor[i*j].push_back(i);
for(int i=1;i<=n;i++){
    for(int j=0;j<factor[i].size();j++)
        printf("%d ",factor[i][j]);
    printf("\n");
}

(5)倍数法的推论

1~N每个数的约数个数总和,大约为N*logN。

 

【例题】洛谷 p1403 约数研究

< 法1 > 倍数法筛因子个数

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

/*【洛谷p1403】约数研究【法1:倍数法筛因子个数】
f(n)表示n的约数个数,现在给出n,要求求出f(1)到f(n)的总和。 */

int p[1000100],n;

void reads(int &x){ //读入优化(正负整数)
    int f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f; //正负号
}

void init(){ //倍数法求因数个数
    memset(p,0,sizeof(p));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n/i;j++)
            p[i*j]++;
}

int main(){
    int sum=0; reads(n); init();
    for(int i=1;i<=n;i++) sum+=p[i];
    printf("%d\n",sum);
}

< 法2 > 归纳统计法

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

/*【洛谷p1403】约数研究
f(n)表示n的约数个数,现在给出n,要求求出f(1)到f(n)的总和。 */

void reads(int &x){ //读入优化(正负整数)
    int f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f; //正负号
}

int main(){
    int n,sum=0; reads(n);
    for(int i=1;i<=n;i++) sum+=n/i;
    printf("%d\n",sum);
}

 

【例题】 bzoj 1053 Antiprime数

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;

/*【bzoj1053】caioj 1411 打牌
对于任何正整数x,其约数的个数记作g(x)。例如g(1)=1、g(6)=4。
如果某个正整数x满足:g(x)>g(i) 0<i<x,则称x为反质数。
例如,整数1,2,4,6等都是反质数。
现在给定一个数N,你能求出不超过N的最大的反质数么 */

/*【分析】通过计算可以得出,
一个2000000000以内的数字不会有超过12
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值