Number Theory(1)
202404
0 前言
离散数学是本书的重点,而整数又是离散数学的中心议题。数论 是讨论整数性质的重要数学分支,因此我们要来探索它。
——《具体数学》第四章
标有 *
的为拓展内容,或者说比较难的题目,但它们都非常有趣。
部分题目的代码是洛谷的提交记录,阅读这篇文章的大多数同学都该能看(若有需要可以找我要)。
没看懂的地方直接问,不排除我会存在手误。
1 基本概念
1.1 整除
两个整数相除,我们自然想去讨论商是否是一个整数。小学生常常期待这个,因为整数比分数写起来好看。
这引出了数论中的基础概念:整除。
如果
同样的,如果
1.2 整值函数
整数是离散数学的支柱,我们常常需要将分数或者任意的实数转换到整数。 ——《具体数学》第三章
我们首先来讨论 底(floor,最大整数)函数和 顶(ceiling,最小整数)函数,对于所有实数
俗称 下取整 和 上取整,底和顶也会在数论中有许多应用,在后续的部分内容中我们也会用到。
我们有时称
尝试在这里就证明一个非常有趣且有用的事实:如果
设
于是只要
画出图来容易发现这是显然的,这里不做证明。
我们发现其实
1.3 带余除法
当
告诉我们,可以将
这里的
我们约定
容易从定义证明这个法则,因为如果
且模数为零时该式显然也为真(两边都是
关于
。 。 。
前两条定义了
这些性质都是耳熟能详的,这里也不做证明。
1.4 同余关系
模运算是数论提供的一种重要工具,我们在上面把它当成二元运算使用,而在这里我们也可以把
由于
同余符号
乘法同样有效,只要处理的对象是整数:
证明直接作差:
这样一来,我们对方程所习惯做的大多数代数运算对同余式都可以运用,但并不是所有运算。除法运算显然不在其中。
以下部分可能会用到之后要讲的内容。
如果
然而在
它的证明是直接在式子两边乘上
进一步观察改变模的想法,我们可以得到另外一些式子:
反过来,如果我们知道对于两个小的模数有
因为如果
注意关注这个式子的特殊情形
2 欧几里得
有着我们熟悉的
2.1 欧几里得算法(gcd)
欧几里得算法,又称辗转相除法,常用递归得到最大公因数。
而这是容易简单证明的:
设
于是
由于
这样一来,
CF1806F2 GCD Master (hard version)
给定
和一个长度为 的序列 。 定义一次对一个长度为
的序列的操作为,选择序列中两个下标 ,删去 与 ,然后在序列末端加入 。 例如,对于
,一次操作可以选择下标 与 ,这样操作后,序列变成 。 给定
,求对序列 执行 次操作后得到序列中的数的和的最大值。
。
感谢🐨的供题。
首先我们考虑有相同的数如何处理?
发现我们对相同的数操作,相当于删去一个,进而在后面的讨论中我们发现其实相同的数并无意义,所以我们最后枚举删了几个相同的数就可以了,于是我们就只需要对不相同的数进行操作即可。
考虑每一次操作,删除两个数
那么这个问题就被转化成把数分成若干组,删去这一组并加上它们的
我们如何让分组最优?不难猜到把所有的分成一组。
假设现在我们存在两组
我们尝试合并两组,也就是把
由于
一定是成立的,所以合并两组一定更优,于是我们就得到了这一结论。
这样我们就可以取枚举
但在这道题中,依次枚举
假设我们现在加入一个没有选的最小的数
因为元素互不相同,所以
于是这样的调整一定是更优的。
这就意味这什么呢?
假设我们选了
也就是说我们只需要枚举选了多少个数和最大的数选的是什么就可以了。但这样还是会 T。
考虑把
双倍经验:CF1806F1 GCD Master (easy version)。
2.2 扩展欧几里得算法(exgcd)
扩展欧几里得算法,即 exgcd,旨在求不定方程
关于一个不定方程
如果
均为整数,则有整数 满足 。
证明是简单的,我们设
容易发现,如果
同时,根据 裴蜀定理 我们可以得到一个推论:
两个整数
互质,当且仅当 存在解 。
那如何求这组方程
我们考虑欧几里得算法的递归过程
当递归结束时
所以我们可以尝试先递归去求
那么
于是这就可以在欧几里得算法中解决了。
int exgcd(int a,int b,int &x,int &y){
if(b==0) return x=1,y=0,a;
int d=exgcd(b,a%b,y,x);
y-=a/b*x;return d;
}
那么我们如何从一组解推广到更多组解呢?(这样可以方便找到一组最小正整数解)
我们用 exgcd 得到了一组解
对于
所以
通过这样的调整,我们就可以找到想要的解了。
而回到最初,如果
P1082 [NOIP2012 提高组] 同余方程
求关于
的同余方程 的最小正整数解。
整理一下方程,即将同余拆开,我们可以得到
那么下面这个东西是直接可以用 exgcd 解决的,于是你就做完啦!
那如何找到最小整数解呢?
根据上面的转化,其实就是找到最小的
然后你就会求逆元了!
ABC340F S = 1
给你整数
和 ,它们至少满足 和 中的一个。 请找出一对满足以下所有条件的整数
。如果不存在这样的一对,请报告。
- 在
平面上,顶点为 的三角形的面积为 。
。
机翻的,还能看。一场非常近的 ABC,有些人在场上。
考虑如何计算这三个点组成的三角形面积呢?
用四边形面积直接减去三个角上的三角形,于是可以得到
而由于我们只考虑了一种象限的情况,所以
题目要求
2.3 类欧几里得算法
设
其中
这个式子和《具体数学》3.5 中的例三相当像啊,也就是说当
但是先不急,我们先把类欧几里得算法推完再来讨论这个问题。
如果
我们就把
接下来,用一些处理和式和处理底和顶的技巧
设
这就是一个递归的式子了,交换了
这也就是欧几里得算法的辗转相除过程,于是类欧几里得名字就是这样来的。
接下来我们对于类欧几里得算法进行一个推广,尝试去求另外两个和式:
首先来推导
接下来考虑
设
接着,我们推导
考虑
考虑
那么
还是设
三个函数一起进行递归,于是你就可以通过 P5170 【模板】类欧几里得算法 啦!代码。
const ll mod=998244353,i2=499122177,i6=166374059;
ll T,a,b,c,n;
struct node{
node () {f=g=h=0;}
ll f,g,h;
}ans;
node calc(ll a,ll b,ll c,ll n){
ll ac=a/c,bc=b/c,m=(a*n+b)/c,in=n*(n+1)%mod*(2*n+1)%mod*i6%mod;
node res;
if(a==0){
res.f=bc*(n+1)%mod;
res.g=bc*n%mod*(n+1)%mod*i2%mod;
res.h=bc*bc%mod*(n+1)%mod;
return res;
}
if(a>=c||b>=c){
res.f=n*(n+1)%mod*i2%mod*ac%mod+(n+1)*bc%mod;res.f%=mod;
res.g=in*ac%mod+n*(n+1)%mod*i2%mod*bc%mod;res.g%=mod;
res.h=ac*ac%mod*in%mod+bc*bc%mod*(n+1)%mod+ac*bc%mod*n%mod*(n+1)%mod;res.h%=mod;
node e=calc(a%c,b%c,c,n);
res.h+=e.h+2*bc%mod*e.f%mod+2*ac%mod*e.g%mod;
res.g+=e.g;res.f+=e.f;
res.h%=mod;res.f%=mod;res.g%=mod;
return res;
}
node e=calc(c,c-b-1,a,m-1);
res.f=(n*m%mod-e.f+mod)%mod;
res.g=(m*n%mod*(n+1)%mod-e.h-e.f+mod+mod)%mod*i2%mod;
res.h=(n*m%mod*(m+1)%mod-2*e.g%mod-2*e.f%mod-res.f%mod+3*mod)%mod;
return res;
}
P5179 Fraction
给你四个正整数
,求一个最简分数 满足 。 若有多组解,输出
最小的一组,若仍有多组解,输出 最小的一组。
。
一道用到类欧类似思想的题目。
什么时候我们可以不加思考地直接算出这个目标分数?
发现当
举一个例子:
对其取倒数,可以得到
把两边
我们把这两边的分数变成更小的真分数,继续循环:
从而一步一步带回即可。代码。
这道题中我们把假分数转成真分数的操作和类欧类似。
ABC283Ex Popcount Sum
组询问,每组求 内, 余 的数在二进制下 的个数的和。
。
对 (x>>i)&1
那么转化成数学表达式就是
而由于我们只统计
这个东西就是容易用类欧几里得算法在
*当 时的封闭形式
我们来尝试求
的封闭形式,也就是
前置知识:来自《具体数学》3.25 和 3.26。
如何证明这个东西?
你可以看成把
个物品分成 组,那么一定有一些组是 个物品,另外一些就是 个。 而从小到大排好序后,第
组刚好有 个元素。
同时,我们还可以对这个东西进行推广,用
替换 ,就可以得到一个对所有实数 都成立的恒等式:
首先可以考虑打表,或许你可以发现一些东西,具体可以去看《具体数学》3.5。
而推导时我们可以用刚才推导类欧几里得类似的方法:对
把它拆成整数部分和小数部分就是
考虑把三项分开来求和,对于第一项和第三项,我们都涉及到了
那么证明处理这个神秘东西呢?
容易发现这是简单的,设
于是它所得到的就是把按照某种次序排列的数
所以这个式子的第一部分的和就是
最后一步就用到了上面前置知识中的东西。
而对于第三部分,我们发现它其实就是一个等差数列重复了
中间的第二部分,也是非常简单的,同样是一个等差数列,它的和就是
于是我们要求的封闭形式就找出来了
如果对封闭形式稍作处理,就可以让它关于
就得到这样的互反律
类欧几里得算法,完。
3 同余关系
在前置知识中提到了同余关系的相关法则,那么在这里我们希望对它的理解更为深刻一些。
3.1 费马小定理
费马小定理:
我们知道,
这个式子是在
由于
同时,费马小定理还有一个更通用的表达方式
3.2 逆元
如果一个线性同余方程
容易发现,这个东西可以用上面我们讨论过的 exgcd 直接求解,同时当
这样两种方法都可以做到单次求逆元
而根据前面我们对 exgcd 是否有解的讨论,容易发现
可是有些时候每次都单独求逆元并不能满足我们所需要的时间复杂度,所以这里就有了另外两种求多个数逆元的方法:
-
线性求逆元:
首先我们知道
,我们尝试线性推出 。那么令
,于是 有 。我们将式子两边同时乘上
可以得到:这样就可以做到线性递推求逆元了。时间复杂度
,就可以通过 P3811 【模板】模意义下的乘法逆元 啦! -
线性求
个数 的逆元:利用前缀积求逆元设
是 的前缀积,那么如果我们知道了 的逆元,于是可以从 倒推回去: 。这样每个数的逆元就是
,时间复杂度 ,这种方法在求阶乘的逆元中常常用到。
3.3 二次探测定理
二次探测定理:
如果
我们先不急着讨论这个东西,先来讨论
首先我们应该考虑
所以
这就意味着当
现在,
每个素数都是独立于其他素数的,对于
于是如果
在这个推导过程中,我们已经证明了 二次探测定理 了!
3.4 威尔逊定理
接下来引出一个逆元的应用——威尔逊定理,他会在之后有关素数的判定中有所应用。
这个定理的一半是平凡的:如果
具体来说,在 1.4 我们引入了一个改变模数的式子,也就是如果
威尔逊定理的另一半说的是,
因为
这里
那哪些数的逆元就是它本身呢?
容易发现其实就是问
当
而
3.5 有趣的遗留问题
在上面推类欧几里得算法的一个拓展时,我们希望证明
按照某种次序恰好组成了
的
或许上面已经给出了一些不太严谨的简要证明,我们在这里希望把它写得更完整一些。
首先证明得到前面
从而当
那么现在我们必须指出,那
我们记
而这种情形就是
根据 鸽巢原理,我们就可以轻松证明出这
它可以被理解成在一个环上面每次跳
4 线性同余方程组
求解形如
的 线性同余方程组,在 OI 中有着广泛的应用。
4.1 中国剩余定理(CRT)
中国剩余定理全称 Chinese Remainder Theorem,简称 CRT。它用于求解 模数两两互质 的线性同余方程组,即对于任意
首先我们来看一个例子:
在《孙子算经》中有这样一个问题:“今有物不知其数,三三数之剩二(除以
余 ),五五数之剩三(除以 余 ),七七数之剩二(除以 余 ),问物几何?
CRT 的步骤是这样的:
-
找出三个数:
从
和 的公倍数中找出被 除余 的最小数 ;从
和 的公倍数中找出被 除余 的最小数 ;从
和 的公倍数中找出被 除余 的最小数 。 -
用
( 为最终除以 的余数),用 ( 为最终除以 的余数),用 。 -
把以上三个数相加得到
,再用它除以 的最小公倍数 ,得到余数 即为最小满足条件的数。
它为什么对的呢?
我们假设
从
同理我们可以得到:
除以 余 ,且是 和 的公倍数。 除以 余 ,且是 和 的公倍数。 除以 余 ,且是 和 的公倍数。
所以 CRT 用数学表示出来就是:
设
因为
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=15;
int n;
ll p,a[N],b[N],m,x,y,ans=0;
void exgcd(ll a,ll b ,ll &x,ll &y){
if(b==0){x=1,y=0;return;}
exgcd(b,a%b,y,x);y-=a/b*x;
}
int main(){
scanf("%d",&n);m=1ll;
for(int i=1;i<=n;i++){
scanf("%lld%lld",&a[i],&b[i]);
m*=a[i];
}
for(int i=1;i<=n;i++){
p=m/a[i];
exgcd(p,a[i],x,y);
ans+=b[i]*p*(x<0?x+a[i]:x);
}
printf("%lld\n",ans%m);
return 0;
}
4.2 扩展中国剩余定理(exCRT)
如果就是单纯的 线性同余方程组 怎么解呢?也就是
这就是 exCRT 所解决的问题,它能解决的东西更为普遍,故使用范围也会更广。
先考虑只有两个方程的简单情况。
容易发现
那么这就是一个可以用 exgcd 求解的方程了。
如果
否则,我们可以得到新的方程,也就是合并了两个方程:
推广到
我们就成功求解了 线性同余方程组!
P4777 【模板】扩展中国剩余定理(EXCRT) 的代码。
ll mul(ll a,ll b,ll m){
ll res=0ll;
while(b){if(b&1) res=(res+a)%m;a=(a+a)%m;b>>=1;}
return res;
}
ll exgcd(ll a,ll b, ll &x,ll &y){
if(b==0){x=1,y=0;return a;}
ll d=exgcd(b,a%b,y,x);y-=(a/b)*x;return d;
}
ll wrk(){
ll ans=a[1],M=b[1];
for(int i=2;i<=n;i++){
ll A=M,B=b[i],C=(a[i]-ans%B+B)%B;
ll gcd=exgcd(A,B,x,y),bg=B/gcd;
if(C%gcd!=0) return -1;
x=mul(x,C/gcd,bg);
ans+=x*M;M*=bg;
ans=(ans%M+M)%M;
}
return (ans%M+M)%M;
}
本文作者:H_W_Y
本文链接:https://www.cnblogs.com/H-W-Y/p/18203501/NumberTheory1
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步