浅谈同余2(扩展欧几里得,中国剩余定理,BSGS)

上一篇:1()

(https://www.cnblogs.com/xyy-yyds/p/17418458.html)

下一篇:  3(BSGS)

(https://www.cnblogs.com/xyy-yyds/p/17418478.html)

0x20 扩展欧几里得 O(log(a+b))
裴蜀定理:
对于任意一对整数a,b, 存在一对整数x,y, 满足ax+by=gcd(a,b)

证明:
在欧几里得算法的最后一步时,b=0,gcd(a,0)=a, 显然x=1,y=0
b>0, 则gcd(a,b)=gcd(b,amodb),假设存在一对整数x,y, 满足bx+(amodb)y=bx+(aba/b)y=ayb(xa/by), 所以令x=y,y=xa/by, 就得到了ax+by=gcd(a,b)
证毕, x,y的计算方法就是扩欧的计算方式
Code:

复制代码
int exgcd(int a, int b, int &x, int &y) { if (!b) { x = 1, y = 0; return a; } int d = exgcd(b, a % b, y, x); //y, x传好算 y -= a / b * x; return d; }
复制代码

扩展欧几里得解线性同余方程

a×xb(modm)的一组解x

a×x=b+m×y
yy
a×x+y×m=b
直接扩欧求出gcd(a,m)的解后,把x扩大b/gcd(a,m)倍即可,然后取模
有解仅当gcd(a,m)|b
Code:

复制代码
int exgcd(int a, int b, int &x, int &y) { if (!b) { x = 1, y = 0; return a; } int d = exgcd(b, a % b, y, x); y -= a / b * x; return d; } int d = exgcd(a, m, x, y); if (b % d) puts("impossible"); else printf("%d\n", (long long)b / d * x % m);
复制代码

 

0x30 中国剩余定理 O(nlogV),V=maxi=1nmaxai,mi
m1,m2,m3,...,mn两两互质, m=i=1nmi,Mi=m/mi,ti是线性同余方程Miti1(modmi)的一个解。对于任意的n个整数a1,a2,a3,...,an, 方程组
{xa1(modm1) xa2(modm2) xa3(modm3) ... xan(modmn) 

用整数解,解为x=i=1naiMiti (摘自《算法竞赛进阶指南》)

Code:

复制代码
void exgcd(ll a, ll b, ll &x, ll &y) { if (!b) { x = 1, y = 0; return ; } exgcd(b, a % b, y, x); y -= a / b * x; } int main() { scanf("%d", &n); M = 1; for (int i = 1; i <= n; i ++ ) scanf("%d %d", m + i, a + i), M *= m[i]; for (int i = 1; i <= n; i ++ ) { ll Mi = M / m[i]; ll ti, y; exgcd(Mi, m[i], ti, y); res += a[i] * Mi * ti; } printf("%lld", (res % M + M) % M); return 0; }
复制代码

0x40 BSGS算法(Baby Step, Giant Step) O(m)

解高次同余方程ax(modm)的最小整数解

x=i×tj, 其中t=m,0jt1, 则方程变成ai×tjb(modm),即atib×aj(modm)
对于所有j, 把aj×bmodm插入Hash
然后枚举i,判断即可

Code:

复制代码
int baby_step_giant_step(int a, int b, int p) { map<int, int> hash; hash.clear(); b %= p; int t = (int)sqrt(p) + 1; for (int i = 0; i < t; i ++ ) { int val = (LL)b * qmi(a, i, p) % p; hash[val] = i; } a = qmi(a, t, p); if (!a) return !b ? 1 : -1; for (int i = 0; i <= t; i ++ ) { int val = qmi(a, i, p); int j = hash.find(val) == hash.end() ? -1 : hash[val]; if (j >= 0 && i * t - j >= 0) return i * t - j; } return -1; }
复制代码

 


__EOF__

本文作者xyy's blog
本文链接https://www.cnblogs.com/xyy-yyds/p/17418472.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   xuyiyang  阅读(38)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示