扩展欧几里得模板 poj-C Looooops

17 篇文章 0 订阅
2 篇文章 0 订阅

poj撸了三个专题了虽然前几个很难但还可以自己想出来,到数论这都是坎,只能看题解慢慢学了。。。
总结下知识点
1 欧几里得定理 GCD(a,b) = GCD(b,a%b) 代码实现渣渣我都能毫不思考的打出来了。
2 ax+by = gcd(a,b)有解 同理可推出 ax+by=c有解的充要条件是c%gcd(a,b)=0;
ax+by=gcd(a,b)通解为x = x0+b/gcd(a,b)*t,y = y0-a/gcd(a,b)*t,这公式可以求出所有的解,x0+bt则不能,可以自己想出来;
3核心是欧几里得的扩展
(1) ax+by = gcd(a,b);
bx1+a%by1 = gcd(b,a%b) = gcd(a,b) = ax+by;
bx1+(a-a/b*b) *y1 = ax+by
ay1+b(x1-a/b*y1) = ax+by
x = y1;
y = x1-a/b*y1;
此公式递推出x,y;
(2)递推肯定有起点,起点是gcd(a,b)x+0*y=gcd(a,b)
此时y=0,x=1; 当然y也可以是别的乱七八糟的,但0更省事;
(3)最后求出x 通解为x+b/gcd(a,b)*t, t为任意整数

int x,y;
int e_gcd(int a,int b)
{
    if(b==0)
    {
       x = 1;
       y = 0;
       return a;
    }
    int ans = e_gcd(b,a%b);
    int t = x;
    x = y;
    y = t-a/b*y;
    return ans;
}  //求通解
//by blacktea 11/22/2015
//扩展欧几里得模板
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<ctime>
using namespace std;
__int64 a,b,c,k,x,y;
__int64 e_gcd(__int64 a,__int64 b)
{
    if(!b){
         x = 1;
         y = 0;
         return a;
    }
    __int64 ans = e_gcd(b,a%b);
    __int64 t =x;
    x = y;
    y = t-a/b*y;
    return ans;
}
//扩展欧几里得核心代码
int main()
{
    while(scanf("%I64d %I64d %I64d %I64d",&a,&b,&c,&k))
    {
        if(!a&&!b&&!c&&!k)break;
        __int64 mod = (__int64)1<<k;
        __int64 g = e_gcd(c,mod);
        if((b-a)%g)printf("FOREVER\n");
        else
        {
            x=(b-a)/g*x;
            __int64 s=mod/g;
            x = (x%s+s)%s;//求x所有解中的为正数中的最小值 同时考虑x起始为负的情况
            printf("%I64d\n",x);
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
扩展欧几里得算法是求解一元一次不定方程 ax + by = gcd(a,b) 的一种方法,其中 a 和 b 是整数,gcd(a,b) 是它们的最大公约数,x 和 y 是整数解。逆元是指在模运算下,一个数的乘法逆元是指与它相乘后模运算得到 1 的数。在数论中,常常需要求一个数在模意义下的逆元,即一个数 k 满足 (k * x) % m = 1,其中 m 是模数。 下面是扩展欧几里得算法求逆元的 C 语言实现: ```c #include <stdio.h> // 扩展欧几里得算法 int exgcd(int a, int b, int *x, int *y) { if (b == 0) { *x = 1; *y = 0; return a; } int gcd = exgcd(b, a % b, y, x); *y -= a / b * (*x); return gcd; } // 求逆元 int modinv(int a, int m) { int x, y; int gcd = exgcd(a, m, &x, &y); if (gcd != 1) { return -1; // a 和 m 不互质,不存在逆元 } else { return (x % m + m) % m; // 转化为正整数 } } int main() { int a = 3, m = 11; int inv = modinv(a, m); if (inv == -1) { printf("%d 在模 %d 意义下不存在逆元\n", a, m); } else { printf("%d 在模 %d 意义下的逆元是 %d\n", a, m, inv); } return 0; } ``` 这个程序中,exgcd 函数通过递归实现扩展欧几里得算法,返回 a 和 b 的最大公约数,并且求出 x 和 y 的值。在 modinv 函数中,我们调用 exgcd 函数求出 a 和 m 的最大公约数,并且判断 a 和 m 是否互质,如果不互质则不存在逆元。否则,根据扩展欧几里得算法的结果,求出 x 的值作为 a 在模 m 意义下的逆元。注意,由于 x 可能是负数,所以要将其转化为正整数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值