• POJ 1061


    题意

    两只青蛙A,B在一条纬度上,纬度线总长为L,A在x处,B在y处。他们同时朝西走,A每次能走m,B每次能走n。问这两只瓜皮青蛙是否有可能相遇,如果不能相遇输出”Impossible”,如果能相遇则输出跳跃的次数。

    思路

    这题虽然是个数论基础题,但是恶心了我零零碎碎快一天的时间…到最后POJ还挂了交不上去。先记录一下大体的思路吧。之后再补代码。

    首先,建模过程还是非常愉悦的:
    设跳了t次相遇,此时A蛙所在的位置为 (x+nt)%L,B蛙所在位置为 (y+mt)%L
    AB相遇即 (x+mt)modL=(y+nt)modL
    他们相减一定是纬度线长度的整数倍,设为k*L
    (mn)t+kL=yx
    设a = m-n, b = L, c = y-x, 化为ax+by=c问题
    令d = gcd(a, b, x, y)
    如果d % c != 0 无解,否则有解

    exgcd
    扩展欧几里得算法,简称 exgcd,一般用来求解不定方程求解线性同余方程求解模的逆元
    引理:存在 x , y 使得 gcd(a,b)=ax+by
    证明:
    当 b = 0 时,gcd(a,b) = a,此时 x = 1 , y = 0
    当 b != 0 时,
    设 ax1 + by1 = gcd(a,b) = gcd(b,a%b) = bx2 + (a%b)y2
    a%b = a - [floor(a/b)] * b
    //特意这么写是因为我居然被这个公式卡了很久
    则 ax1 + by1 = bx2 + ( a - a/b * b )y2
    ax1 + by1 = bx2 + ay2 - a/b * by2
    ax1 + by1 = ay2 + bx2 - b * a/b * y2
    ax1 + by1 = ay2 + b( x2 - a/b * y2 )
    根据恒等定理解得 x1=y2 , y1=x2-a/b*y2
    因为当 b=0 时存在 x , y 为最后一组解
    而每一组的解可根据后一组得到
    所以第一组的解 x , y 必然存在
    得证
      
    根据上面的证明,在实现的时候采用递归做法
    先递归进入下一层,等到到达最后一层即 b=0 时就返回x=1 , y=0
    再根据 x=y’ , y=x’-a/b/y’ ( x’ 与 y’ 为下一层的 x 与 y ) 得到当层的解
    不断算出当层的解并返回,最终返回至第一层,得到原解
    参考:欧几里德与扩展欧几里德算法
    欧几里得算法与扩展欧几里得算法_C++
    exgcd题集:扩展欧几里得专题

    exgcd 模板
    int exgcd(int a, int b, int& x, int& y){
        int d = a;
        if( b != 0 ){
            d = exgcd(b, a%b, y, x);
            y -= (a / b)*x;
        }
        else{
            x = 1; y = 0;
        }
        return d;
    }

    剩下的就是套个线性同余板子求解最小正整数解即为所求的 t

    关于这道题目的缜密证明:POJ1061 青蛙的约会
    关于这道题目的具体分析:POJ 1061青蛙的约会题解

    AC代码

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    typedef long long ll;
    
    ll exgcd( ll a, ll b, ll& x, ll& y ){
        if( b == 0 ){
            x = 1;
            y = 0;
            return a;
        }
        ll r = exgcd(b, a%b, x, y);
        ll t = x;
        x = y;
        y = t - a/b*y;
        return r;
    }
    
    int main()
    {
        ll a, b, c, xx, yy, m, n, l;
        scanf("%lld%lld%lld%lld%lld",&xx, &yy, &m, &n, &l);
        // 设次数为t, 模常数k
        // (m-n)t + kl = y-x
        //  at+bk = c
        a = m - n;
        b = l;
        c = yy - xx;
        if( a < 0 ){
            a = -a;
            c = -c;
        }
        ll x, y;
        ll d = exgcd(a, b, x, y);
        if( c % d != 0 )
            puts("Impossible");
        else{
            x=x*(c/d)%b;
            x=(x%(b/d)+(b/d))%(b/d);
            printf("%lld
    ", x);
        }
        return 0;
    }
  • 相关阅读:
    基础的mybatis学习
    NLP之知识图谱
    Global Azure 2022 China
    vs2015 /cshtml文件出现“当前上下文不存在名称ViewBug”问题
    vue中a的href写法
    (转)Ceph 的发展历程及版本信息
    推荐一款新框架PyScript:在 HTML 嵌入 Python 代码!
    C# 给Word中的字符添加强调符号(着重号) E
    C#/VB.NET 实现Word和ODT文档相互转换 E
    中国股市:炒股耐心比什么都重要,值得
  • 原文地址:https://www.cnblogs.com/JinxiSui/p/9740559.html
Copyright © 2020-2023  润新知