【笔记+模板】 数论

部分概念引自百度百科和各位神犇资料,侵删。

无特殊说明,基本都在mod意义下

逆元

定义:

逆元素是指一个可以取消另一给定元素运算的元素,在数学里,逆元素广义化了加法中的加法逆元和乘法中的倒数。
在模运算中 ax=1(mod p)x就是a在%p意义下的逆元。

解法:

1.费马小定理

2.exgcd
参照同余方程一题。
ax=1(mod p)
x即为a的逆元,转成exgcd求解x

费马小定理

内容:

p是质数,gcd(a,p)=1,a^(p-1)=1(mod p);

证明:

感谢某位数学大佬(虽然我看不懂)
这里写图片描述

应用:

这里写图片描述

a的逆元即为a^(p-2)

欧拉函数

定义:

φ(i)表示小于i的正整数中与i互质的数的数目,φ(1)=1。

欧拉定理:

费马小定理是欧拉定理的特殊情况,oi用的不多,,,,不写了。

公式:

通式:
这里写图片描述
这里写图片描述

解释:
1.当i为质数 φ(i)=i-1;
2.第一行,由上一页的递推式不断展开
3.第二行,可以理解为将n质因数分解,然后把括号里的同*pk,指数-1;

素性判定

定理基础:

利用费马小定理的逆定理,随机a,可以判断p是否为素数,但是,正确率较低。

二次探测定理:
若p 是素数,x 是一个整数,且x^2 mod p 1,那么x =1/-1 (mod p)
这里写图片描述
以上,都在mod p意义下
第三行,左侧有因数p,那么右侧(x-1)或(x+1)中必定有一部分中有因数p,即某一部分是p的倍数,
x+1是p的倍数:x=-1;
x- 1是p的倍数:x=1;
即:一个质数不存在非平凡平方根(就是除了1,-1没有数x的平方根=质数p)
可以通过类似23^2 = 1 (mod 66) 的条件判断66 不是质数,增
加正确性

Miller Rabin 算法

a可以取2~25内质数,不必要随机。
图1
这里写图片描述
图2

首先,若p是质数,a^p-1=1,即“然后是一堆奇奇怪怪的1”
显然图1中的a^x序列是等比数列,公比为2;
1只能有1,-1两种情况平方而来,
图2中的第一个判断,去除由1平方到1的情况。(return true表示该数为质数)
第二个判断,去除了由-1平方到1的情况;
剩下的情况:要么不满足费马小,要么由一个非-1的数跳转到1(在mod p意义下是可能的,如23^2=1 mod 66),都是错误的;

中国剩余定理

这里写图片描述

这里写图片描述
显然,不证。
R/B,A已知,求k转化为同余方程,用exgcd求解。

积性函数

定义:

如果一个数论函数f(x) 满足对于任意的互质正整数n,m 均有
f(nm) = f(n)f(m), 则称为积性函数。
如果一个数论函数f(x) 满足对于任意的正整数n,m 均有
f(nm) = f(n)f(m), 则称为完全积性函数。

栗子:

模n 意义下的逆元inv(x):完全积性函数
欧拉函数phi(x): 积性函数
因数个数函数: 积性函数
因数和函数: 积性函数
莫比乌斯函数mu(x): 积性函数//这个忽视掉吧qwq

证明:快下课了,不写了(好吧我就是不想写)

用线性筛搞出所有积性函数

先粘一波mhy的代码

#include<iostream>
using namespace std;
#define MAXN 30
bool pflag[MAXN];
int prime[MAXN],topp=-1;
int phi[MAXN];
int g[MAXN],gg[MAXN];
int mnprime[MAXN];

void init()
{
    phi[1] = 1;
    g[1] = gg[1] = 1;
    for (int i=2;i<MAXN;i++)
    {
        if (!pflag[i])
        {
            prime[++topp] = i;
            phi[i] = i-1;
            g[i] = 1;
            gg[i] = i+1;
            mnprime[i] = i;
            inv[i] = pow_mod(i,p-2);
        }
        for (int j=0;j<=topp && i*prime[j]<MAXN;j++)
        {
            printf("%d*%d -> %d\n",i,prime[j],i*prime[j]);
            pflag[i*prime[j]] = true;
            mnprime[i*prime[j]] = prime[j];
            inv[i*prime[j]] = inv[i] * inv[prime[j]];
            if (prime[j] == mnprime[i])
            {
                g[i*prime[j]] = g[i];
                gg[i*prime[j]] = (gg[i] * prime[j] + 1);
            }else
            {
                g[i*prime[j]] = g[i] * gg[i];
                gg[i*prime[j]] = prime[j]+1;
            }
            if (i%prime[j] == 0)
            {
                phi[i*prime[j]] = phi[i] * prime[j];
                break;
            }else
            {
                phi[i*prime[j]] = phi[i] * (prime[j]-1);
            }
        }
    }
}

int main()
{
    freopen("output.txt","w",stdout);
    init();
    /*
    for (int i=0;i<=topp;i++)
        printf("%d ",prime[i]);
    printf("\n");
    */
    for (int i=1;i<MAXN;i++)
    {
        printf("%d: phi=%d sum=%d g=%d gg=%d\n",i,phi[i],g[i]*gg[i],g[i],gg[i]);
    }
}

欧拉函数:

这里写图片描述

首先:线性筛中的每一个合数,都是被他的最小的质因子筛掉的。
根据欧拉函数的通式,令x=i*prime[j];
i%prime[j] == 0,那么i中已有prime j,故prime是x的一个指数不为1的质因子,且phi[i]中已有pk-1,所以prime对phi[x]的贡献为公式中的指数+1,即prime[j]
若不为0,那么i中没有prime,prime是x的一个指数为1的质因子,对phi x贡献为prime-1


void init()
{
    phi[1] = 1;
    for (int i=2;i<MAXN;i++)
    {
        if (!pflag[i])
        {
            prime[++topp] = i;
            phi[i] = i-1;//质数的欧拉函数值 
        }
        for (int j=0;j<=topp && i*prime[j]<MAXN;j++)
        {
            pflag[i*prime[j]] = true;
            if (i%prime[j] == 0)
            {
                phi[i*prime[j]] = phi[i] * prime[j];
                break;
            }else
            {
                phi[i*prime[j]] = phi[i] * (prime[j]-1);
            }
        }
    }
}

逆元:
完全积性函数,直接*
因数和:
质数的因数和=本身+1;
维护一个x的最小质因子mnprime,g为x除了mnp以外的质因子的因数和的乘积,gg为mnp的因数和。

void init()
{

    g[1] = 1; 
    gg[1] = 1;
    for (int i=2;i<MAXN;i++)
    {
        if (!pflag[i])
        {
            prime[++topp] = i;
            g[i] = 1;
            gg[i] = i+1;
            mnprime[i] = i;

        }
        for (int j=0;j<=topp && i*prime[j]<MAXN;j++)
        {
            pflag[i*prime[j]] = true;
            mnprime[i*prime[j]] = prime[j];//被最小的质因子筛
            if (prime[j] == mnprime[i])
            {
                g[i*prime[j]] = g[i];//除了mnp的因数和之积不变
                gg[i*prime[j]] = (gg[i] * prime[j] + 1);
//2为例,本来是(12),多了一个2,质因子变成了4,因数和变成了(1,2,4),即本来的*2,再加上2^0=1;
            }else
            {
                g[i*prime[j]] = g[i] * gg[i];//g加入了以前的gg,*起来
                gg[i*prime[j]] = prime[j]+1;//gg更新为当前的prime+1
            }
            if (i%prime[j] == 0)    break;
        }
    }
}

筛法

欧拉筛 O(n)线性筛

void oulashai(){
    for(int i=2;i<=n;i++){
        if(!vis[i]) pri[++tot]=i;
        for(int j=1;j<=tot;j++){
            int m=i*pri[j];
            if(m>n) break;
            vis[m]=1;
            if(!i%pri[j]) break;
        }
    }
}

埃氏筛 O(n*loglogn)

void aishai(){
    for(int i=2;i<=n;i++){
        if(!vis[i]) pri[++tot]=i;
        for(long long j=i*i;j<=n;j+=i)
            vis[j]=1; 
    }
}

快速幂

long long pow_mod(int a,int b){//a^b
    long long ans=1;
    while(b){
        if(b&1) ans=ans*a;
        a*=a;
        b>>=1;
    }
    return ans;
}

gcd有关

gcd

代码
风骚的一行写法
int gcd(int a,int b){
    return a%b==0 ? b : gcd(b,a%b);
}
证明
令a=kb+r r=a-kb  r=a%b 
设 d是a,b的公共约数,d|b,d|a;
r=a-kb 
r/d=a/d-kb/d  普通意义下的除法 
a/d,kb/d是整数--->r/d是整数
d是r的约数 
所以gcd(a,b)==gcd(b,r)==gcd(b,a%b) 

exgcd

代码
void exgcd(int a,int b,int &x,int &y){

    if(b==0){
        x=1;
        y=0;
        return ;
    }
    exgcd(b,a%b,x,y);
    int tmp=y;
    y=x-(a/b)*y;
    x=tmp;
    return ;
}
证明:
                ax+by=gcd(a,b)

          bx1+(a%b)y1=gcd(b,a%b)

    bx1+(a-(a/b)*b)y1=gcd(b,a%b)//整除
    bx1+ay1-(a/b)*by1=gcd(b,a%b)
   ay1+b(x1-(a/b)*y1)=gcd(b,a%b)    ① 
                ax+by=gcd(a,b)      ②
    ①== ②
    x=y1,y=x1-(a/b)*y1; 

序列问题

错排

推导式
d[1]=0,d[2]=1;
d[n]=(n-1)*(d[n-1]+d[n-2])

定义
考虑一个有n个元素的排列,若一个排列中所有的元素都不在自己原来的位置上,那么这样的排列就称为原排列的一个错排。 n个元素的错排数记为D(n)。 研究一个排列错排个数的问题,叫做错排问题或称为更列问题。

证明:
对于第n个元素,考虑把它放在第k位上(k有n-1中方案)
记k位上本来的元素为g
若g放在n上 除了n,k以外的n-2位元素错排
若g不放在n上 除了n以外的n-1位元素错排 (此时g不能放的位置是n而不是k,k位已经被n占据,不在考虑范围内)

d[n]=(n-1)*(d[n-1]+d[n-2])

由于d值的大小可以表示概率的大小,因此不需考虑k放在n位和不放在n位的概率问题。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值