「裴蜀定理」学习笔记

定义

a,b 是不全为 0 的整数

1.对任意整数 x,y,满足 gcd(a,b)|ax+by

2.存在整数 x,y 使得 ax+by=gcd(a,b)

证明

第一条

理解一下即可,比较好理解


第二条

  1. 若任何一个等于 0,则 gcd(a,b)=a,这时定理显然成立

  2. a,b 均不等于 0

    由于 gcd(a,b)=gcd(a,b),不妨设 a,b>0abd=gcd(a,b)

    对于 ax+by=d,两边同时 ÷d,可得 a1x+b1y=1,由于除以了 a,b 的最大公约数,所以此时 a,b 互质,转证 a1x+b1y=d

    回顾 exgcd 中辗转相除的思想:

    gcd(a,b)gcd(b,amodb),将模出来的数称作 r,则:

    gcd(a1,b1)=gcd(b1,r1)=gcd(r1,r2)==gcd(rn1,rn)=1

    将上述式子转换为带余数的除法

    a1=q1b1+r1

    b1=q2r1+r2

    r1=q3r2+r3

    rn3=qn1rn2+rn1

    rn2=qnrn1+rn

    rn1=qn+1rn

    当辗转相除法除到互质时,rn=1,以 x 替换 q,则有:

    rn2=xnrn1+1

    1=rn2xnrn1

    将倒数第三个式子转化为 rn1=rn3xn1rn2,代入上式

    1=rn2xn(rn3xn1rn2)

    1=(1+xnxn1)rn2xnrn3

    然后通过同样方法消去 rn2,,r1

    可证得 1=a1x+b1y 是一般式中 d=1 的情况

    同时乘以 d,得 ax+by=d

推广

逆定理

a,b 是不全为 0 的整数,d>0a,b 的公因数,且存在整数 x,y,使得 ax+by=d 成立,则 d=gcd(a,b)

特殊的,当上述的 d=1 时,则 a,b 互质


多个整数

n 个整数的情形:设 a1,a2,,an 是不全为 0 的整数,则存在整数 x1,x2,,xn ,使得 i=1ndiai=gcd(a1,a2,,an)


其逆定理也成立:设a1,a2,,an 是不全为 0 的整数,d>0 是她们的公因数,若存在整数 x1,x2,,xn,使得 i=1ndiai=gcd(a1,a2,,an),则 d=gcd(a1,a2,,an)

例题:

简化题意:

给定序列 a,求满足 r=(i=1ndiai)modkr 的个数和所有情况


解法

根据上述证明的裴蜀定理,得到序列 x 满足 i=1nxiai=gcd(a1,a2,,an),且 gcd(a1,a2,,an)|i=1nxiai

d=gcd(a1,a2,,an),于是设 i=1nxiai=dl=kh+r

建立一个不定方程 dl=kh+r,移项得 dlkh=r,用 x 替换 ly 替换 h,得到 dx+ky=r

根据裴蜀定理,方程有解当且仅当 gcd(d,k)|r

于是得出 exgcd 的模型 dx+ky=rgcd(d,k)|r,根据 exgcd 的推理过程,当最后一层时 xn=0yn=1,此时 r 最大,r=k

故此,在满足 gcd(d,k)|r 的条件下,r 可以从 0 取到 k(每次+ gcd(d,k)

所以共有 kgcd(d,k) 个满足的 r,依次从 0 输出到 k(每次+ gcd(d,k))即可,也就是第 i(1ikgcd(d,k)) 个解为 (i1)×gcd(d,k)


代码如下

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
template<typename Tp> inline void read(Tp&x)
{
x=0;register bool z=1;
register char c=getchar();
for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
x=(z?x:~x+1);
}
int a,n,k,ans;
int gcd(int a,int b){return b?gcd(b,a%b):a;}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
read(n),read(k);
ans=k;//此处注意!
for(int i=1;i<=n;i++)
read(a),
ans=gcd(ans,a);
cout<<k/ans<<endl;
for(int i=0;i<k/ans;i++)
cout<<i*ans<<' ';
}

注意事项

可见代码中的一行 ans 初始化为 k,已证 ans 必为 gcd(d,k) 的整数倍数,否则方程无解,若没了这条,显然无法保证 ans 与这个 gcd 中的 k 去满足

posted @   卡布叻_周深  阅读(72)  评论(3编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示