线性同余方程

形如 axb(modn) 的方程称为线性同余方程,从区间 [0,n1] 中求解 x.

逆元求解。

假设 gcd(a,n)=1,两边同时乘上 a1 即可。

g=gcd(a,n),左侧始终可以 被 g 整除,若右侧不可则无解。

若右侧可以被 g 整除,则将 a,b,n 同时除以 g,得到 axb(modn).

此时 gcd(a,n)=1,回到上面的情况。

所以解为 xx+in(modn),i[0,g1],个数为 g 个或 0 个。

扩展欧几里得算法求解。

方程可以写成 ax+nk=b,有解的充要条件是 gcd(a,n)|b.

先算出 ax0+nk0=gcd(a,n),之后两边同时除以 gcd(a,n) 再乘上 b 即为一组解。

a=x0gcd(a,n)b,k=k0gcd(a,n)b.

gcd(a,n)=1,ax+nk=b 的一组特解为 x0,k0,则任意解可以写成 x=x0+nt,k=k0at,t 为任意整数。

对于求一个最小整数解,x=(xmodt+t)modt,t=ngcd(a,n)

P2613 【模板】有理数取余

给定 a,b,p,求 c=ab(modp),0<=a<=1010001,1<=b<=1010001.

读入过大,但是是同余方程,可以在读入时将其进行取模,当 bp 的倍数时不存在逆元,分母为零,无解。

constexpr int N=5e6+6,mod=19260817;
template<class T>inline T readmod(T&x){
char c=getchar();x=0;
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),x%=mod,c=getchar();
return x;
}
signed main(){
int a,b,x,y;
readmod(a),readmod(b);
if(b==0){
cout<<"Angry!";
return 0;
}
exgcd(b,mod,x,y);
x=(x%mod+mod)%mod;
cout<<a*x%mod;
return 0;
}

P5656 【模板】二元一次不定方程 (exgcd)

求解二元一次不定方程 ax+by=c.

首先找到特解 ax+by=c,假设将 x 扩大为 x+py 缩小为 yq.

则有,a(x+p)+b(yq)=c,ax+by=c.

解得,p=bqa,q=apb,由于需要获得最小的正整数,所以 a|bq,b|ap.

故,bqmin=apmin=lcm(a,b)=abgcd(a,b).

可以得到 pmin=bg,qmin=ag,也就是 x,y 的最小增幅。

考虑将 x 调整至最小正整数解。

假设 x<0,设 x+kp>=1,则 k>=1xp.

x>1,则 k=x1p.

x 为最小正整数时 y>0,则正整数解的个数为 y1q+1.

注意调整 x,y 是应该系数在前面,p,q 在后面,来避免上下取整造成的误差与错误。

while(t--){
int a,b,c,x,y;
cin>>a>>b>>c;
int g=exgcd(a,b,x,y);
if(c%g){
cout<<-1<<'\n';
continue;
}
x*=c/g;
y*=c/g;
int p=b/g,q=a/g,k;
if(x<0){
k=ceil((1.0-x)/p);
x+=k*p;
y-=k*q;
}
else{
k=(x-1)/p;
x-=k*p;
y+=k*q;
}
if(y>0)cout<<(y-1)/q+1<<' '<<x<<' '<<(y-1)%q+1<<' '<<x+(y-1)/q*p<<' '<<y<<'\n';
else cout<<x<<' '<<y+(int)ceil((1.0-y)/q)*q<<'\n';/*注意要对ceil强制转换才能当做系数*/
}
posted @   半步蒟蒻  阅读(125)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示