zoukankan      html  css  js  c++  java
  • [POJ2115]C Looooops 拓展欧几里得

    原题入口

    这个题要找到本身的模型就行了

    a+c*x=b(mod 2k) ->  c*x+2k*y=b-a

    求这个方程对于x,y有没有整数解.

    如果没有学过,强烈建议看看我之后写的一篇博客!!

    这个只要学过拓展欧几里得(好像有的叫扩展欧几里德QAQ)(求解一次整数方程的整数解)应该是能做出来的,下面简单讲讲

    已知一组二元一次方程 ax+by=c(a,b为已知;x,y未知) 我们要求x和y的整数解。
    这个咋做呢 首先 我们知道 gcd(a,b)=gcd(b,a%b)这个就是朴素欧几里德(辗转相除) ,又知道一个方程ax+by=gcd(a,b)必有解(通过贝祖定理可知(我也不会证明QAQ))。
    这些证明见《数学一本通》或者百度搜搜。
    然后我们就有 ax+by=gcd(a,b)=gcd(b, a%b)
                            =bx+(a%b)y
                            =bx+(a-[a/b]*b)y
                            =bx+ay-[a/b]*by
                            =y*a+(x-[a/b]*y)*b
    最后x变成了y,y变成了x-[a/b]*y
    然后就可以通过不断递归求gcd来减小a,b的范围,到b为0时就有ax+0*y=a。x显然为1,y为0
    在找到最小解之后,递归回去修改x,y。

    当且仅当gcd(a,b)=1这个方程有解。

    一开始对于ax+by=c这种形式的,最好先约(a,b)gcd,最后再给c乘回来

    这个程序最后对于sum进行了操作,这是因为要求sum的最小正整数解。

    这是因为:得到两个相邻x解的间隔恰好为b(这个比较显然的吧。。QwQ),然后最小正整数的x解就为(x%b+b)了2333。(公式没用LaTeX有点丑TAT)

    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #include <cctype>
    #include <iostream>
    #define For(i, l, r) for(int i = (l); i <= (int)(r); ++i)
    #define Fordown(i, r, l) for(int i = (r); i >= (int)(l); --i)
    #define Set(a, v) memset(a, v, sizeof(a))
    #define LL long long
    
    using namespace std;
    
    LL extended_gcd (LL a, LL b, LL &x, LL &y) {
        LL ret, tmp;
        if (!b) {x = 1; y = 0; return a;}
        ret = extended_gcd (b, a%b, x, y);
        tmp = x;
        x = y;
        y = tmp - a / b * y;
        return ret;
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen ("program.in", "r", stdin);
        freopen ("program.out", "w", stdout);
    #endif
        LL a, b, c, k;
        for(;;) {
            scanf ("%lld%lld%lld%lld", &a, &b, &c, &k);
            if (!a && !b && !c && !k) return 0;
            k = (long long) 1 << k;
            LL x, y;
            LL ret = extended_gcd (c, k, x, y); //进行拓欧,求之前写的那个方程有无解
            if ((b - a) % ret != 0) {printf ("FOREVER
    "); continue;} //判断gcd是否为1,判断有无解
            LL sum = (x * (b - a) / ret) % k; //同比扩大的倍数
            sum = (sum % (k / ret) + k / ret) % (k / ret); //求sum的正整数解
            cout << sum << endl;
        }
    }
  • 相关阅读:
    朴素贝叶斯分类-实战篇-如何进行文本分类
    朴素贝叶斯分类-理论篇-如何通过概率解决分类问题
    数据变换-归一化与标准化
    你还不懂傅里叶变换,那就过来掐死我吧
    Python快速入门 ---- 系列文章
    批处理中的时间计算详解
    使用electron+vue开发一个跨平台todolist(便签)桌面应用
    文科妹子都会用 GitHub,你这个工科生还等什么
    如约而至,.NET 5.0 正式发布
    如何进行正确的沟通?
  • 原文地址:https://www.cnblogs.com/zjp-shadow/p/7156484.html
Copyright © 2011-2022 走看看