11.22训练日记

这周我学习了数论的相关内容。数论相比于图论来说,知识点更加的琐碎了,并且对于数学的相关要求比较高(对我这种数学菜的人很不友好)。这周学习的主要知识点有:素数、约数、快速幂、欧拉函数、同余

素数

求素数的方法有很多种:试除法求素数(比较简单,不多说了)、埃氏筛法、线性筛法(埃筛的优化版)、min25筛(太难而且不常用,也不多说了)
埃氏筛法:O(nloglogn)
基本思想为:素数的倍数一定不是素数。
过程:我们可以从2开始枚举,如果当枚举到一个数的时候发现其没有被标记过,那么这个数就是素数。然后我们可以将这个数的倍数全部进行标记。

void get_prime(int x)
{
    for(int i=2;i<=x;i++)
        if(!st[i])					//如果i没有被标记过,说明i是素数
        {
            prime[ans++]=i;
            for(int j=i+i;j<=x;j+=i) st[j]=true;	//标记所有i的倍数
        }
}

但是我们可以很容易的发现:很多数被筛了多次(例如:6被2筛了一次,又被3筛了一次),这样就降低了效率。因此我们可以对它进行一下优化,于是就有了线性筛法。

线性筛法: O(n)
基本思想为:任何一个非素数一定可以被其最小质因子筛掉。

void get_prime(int x)
{
    for(int i=2;i<=x;i++)
    {
        if(!st[i]) prime[ans++]=i;			//如果i未被标记过,则i为素数
        for(int j=0;prime[j]<=x/i;j++)
        {
            st[prime[j]*i]=true;
            if(i%prime[j]==0) break;
        }
    }
}
  1. 如果i%prime[j]==0,因为我们是从小到大枚举的所有素数,因此prime[j]一定是i的最小质因子,那么也就同时说明prime[j]是i * prime[j]的最小值因子。那么说明i * prime[j]是被其最小质因子筛掉的。
  2. 如果i%prime[j]!=0,说明prime[j]一定是小于i的所有质因子的,因此prime[j]一定是i * prime[j]的最小质因子。

通过上面的这两条,线性筛法可以不重不漏的筛出所有的素数,因此时间复杂度为O(n)。

线性筛法可以筛出1-n之间的所有素数,但是我们还可以通过一定的修改,使其能够筛出l-r之间的所有素数来(关于这个问题我还没有完全想明白,后面会补上的)。
相关题目:
夏洛克和他的女朋友
质数距离
阶乘分解

约数

一般与求约数相关的问题有三种:求所有约数(试除法求约数,比较简单),求约数的个数,求约数之和

n=p1k1 * p2k2 * p3k3 * …… * pmkm
一个数可以分解为其所有质因数的km次方的乘积。

约数的个数:
约数的个数即为这些质因子的排列组合。每个质因子可以有0-km种取法,根据乘法原理:一个数约数的个数=(k1+1) * (k2+1) * …… * (km+1)

约数之和:
根据加法原理和乘法原理我们可以得到: 一个数的约数之和=(p10+p11+p12+……+p1k1) * (p20+p21+p22+……+p2k2) * …… * (pm0+pm1+pm2+……+pmkm)。我们将该式展开即可得到这个数的所有约数。

约数有关的题目除了上面的三种之外,还有很多,但其并没有一种固定的形式,遇到了只能是根据数学知识进行推导。
相关题目:
约数个数、约数之和、轻拍牛头、樱花、 反素数、Hankson的趣味题。

快速幂

我们可以通过一个例子来了解快速幂的原理,313怎么求?13个3相乘。
我们可以对它进行一个优化,13=8(23)+4(22)+1(20)。那么313=38+34+31。以上就是快速幂的基本原理了。

int kmi(int a,int k,int mod)	//求a^k%mod的值
{
    int res=1;
    while(k)
    {
        if(k&1) res=(LL)res*a%mod;
        a=(LL)a*a%mod;
        k>>=1;
    }
    return res;
}

快速幂的用途比较固定,就是可以快速的求出ak的值。我感觉它一般是作为一个工具来用的。
相关题目:
序列的
越狱

欧拉函数

定义:对于一个正整数n,小于n且与n互质的正整数(包括1)的个数,记为φ(n)。
欧拉函数的通式:φ(n)=n * (1-1/p1) * (1-1/p2) * (1-1/p3) * (1-1/p4)……(1-1/pk)。 其中,p1,p2……pk为n的所有质因子。

int eular(int x)		//定义求欧拉函数
{
	int ans=x;
	for(int i=2;i<=x/i;i++)
        if(x%i==0)
        {
            ans=ans/i*(i-1);
            while(x%i==0) x/=i;
        }
    if(x>1) ans=ans/x*(x-1);
    return ans;
}

除了定义法求欧拉函数之外,如果要求多个数的欧拉函数,我们就可以用线性筛法来求欧拉函数。

线性筛法求欧拉函数:
线性筛法求欧拉函数其实算是线性筛法的一种扩展应用。要想完全理解其原理,首先就要对线性筛法和欧拉函数的原理有充分的理解。

void get_eulers(int x)
{
    phi[1]=1;					//1的欧拉函数为1
    for(int i=2;i<=x;i++)
    {
        if(!st[i])
        {
            prime[ans++]=i;
            phi[i]=i-1;		//因为i为素数,因此i与1-(i-1)所有数都互质,因此素数i的欧拉函数为i-1。
        }
        for(int j=0;prime[j]<=x/i;j++)
        {
            st[prime[j]*i]=true;
            if(i%prime[j]==0)
            {
                phi[prime[j]*i]=phi[i]*prime[j];
                break;
            }
            phi[prime[j]*i]=phi[i]*(prime[j]-1);
        }
    }
}
  1. i%prime[j]==0时,说明prime[j]是i最小的质因子,也就是说i中包含了prime[j]。因此,prime[j] * i的质因子与i的质因子完全相同。根据欧拉函数的求解公式,因为i和prime[j] * i有相同的质因子,因此φ(i * prime[j])=prime[j] * φ(i)。即phi[prime[j]*i]=phi[i]*prime[j];
  2. i%prime[j]!=0时,说明prime[j]不是i的质因子,但是prime[j]是i * prime[j]的质因子。所以,除去prime[j]之后,i和prime[j] * i的质因子完全相同。因此,φ(i * prime[j])=prime[j] * φ(i) * (prime[j]-1)/prime[j]=φ(i) * (prime[j]-1)。即:phi[prime[j]*i]=phi[i]*(prime[j]-1);

相关题目:
筛法求欧拉函数
可见的点
最大公约数

同余全家桶(同余方程、扩展欧几里得算法、逆元)

扩展欧几里得算法
裴蜀定理:对于任意正整数a和b,一定存在非0整数x,y,使得:ax+by=gcd(a,b)。

扩展欧几里得算法的作用就是求出上述的x和y的一组解。

int exgcd(int a,int b,int &x,int &y)	//返回值为gcd(a,b)
{
    if(!b)
    {
        x=1; y=0;
        return a;
    }
    int t=exgcd(b,a%b,y,x);		//因为b和a互换了位置,因此y和x也要互换位置。
    y-=a/b*x;					//根据下面的数学推导,y要减去a/b*x
    return t;					//t=gcd(a,b)
}
  1. 当b==0时,方程为ax+0y=gcd(a,0)=a。此时,x=1,y=0就是该方程一组解。
  2. 否则要先算出gcd(b,a%b)的值(即gcd(a,b)),方程为by+(a%b)x=gcd(a,b)=by+(a-a/b * b)x。再移相后得:ax+b(y-a/b * x)=gcd(a,b)

同余
同余的定义:三个正整数a,b,m。如果a%m==b%m,则称a和b同余,m称为同余的模。
同余方程ax ≡ b(mod m) //ax%m==b%m,a,b,m都是正整数,求解x的值.
我们也可以这么理解:ax-b是m的整数倍。设y为该倍数,那么ax-b=my,移相得ax-my=b。给y加一个负号,方程改写为ax+my=b,这就是扩展欧几里得算法中提到的二元一次不定方程

该不定方程有解的条件为:b为gcd(a,m)的整数倍
如果b==gcd(a,m)的话,我们可以直接用扩展欧几里得算法求出x和y。但要是b!=gcd(a,m),我们要想算出x和y的值,就需要结合逆元了。

逆元
定义:如果a*x%m=1,那么x即为a的逆元。
假设a’是a的逆元,ax ≡ b(mod m),让两边同上乘上一个a’,得到:aa’x ≡ ba’(mod m) => x ≡ ba’(mod m). 这样我们就求出了x的值了,然后将x的值带入方程即可得到y的值。

相关题目:
同余方程
青蛙的约会
最幸运的数字
曹冲养猪

发现数论是忘得一干二净了,有些会的其实原理之前也没搞明白,只能是先慢慢的把知识点和原理先补上了。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lwz_159

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值