zoukankan      html  css  js  c++  java
  • Codeforces Round #305 (Div. 2)——C拓展欧几里得,循环—— Mike and Frog

    Mike has a frog and a flower. His frog is named Xaniar and his flower is named Abol. Initially(at time 0), height of Xaniar is h1 and height of Abol is h2. Each second, Mike waters Abol and Xaniar.

    So, if height of Xaniar is h1 and height of Abol is h2, after one second height of Xaniar will become  and height of Abol will become  where x1, y1, x2 and y2 are some integer numbers and  denotes the remainder of amodulo b.

    Mike is a competitive programmer fan. He wants to know the minimum time it takes until height of Xania is a1 and height of Abol is a2.

    Mike has asked you for your help. Calculate the minimum time or say it will never happen.

    Input

    The first line of input contains integer m (2 ≤ m ≤ 106).

    The second line of input contains integers h1 and a1 (0 ≤ h1, a1 < m).

    The third line of input contains integers x1 and y1 (0 ≤ x1, y1 < m).

    The fourth line of input contains integers h2 and a2 (0 ≤ h2, a2 < m).

    The fifth line of input contains integers x2 and y2 (0 ≤ x2, y2 < m).

    It is guaranteed that h1 ≠ a1 and h2 ≠ a2.

    Output

    Print the minimum number of seconds until Xaniar reaches height a1 and Abol reaches height a2 or print -1 otherwise.

    Sample test(s)
    input
    5
    4 2
    1 1
    0 1
    2 3
    output
    3
    input
    1023
    1 2
    1 0
    1 2
    1 1
    output
    -1
    Note

    In the first sample, heights sequences are following:

    Xaniar: 

    Abol:

    大意:x = (kx+b)%m 在2*m次里面能看出是否能够到达所有的值

    法一:暴力

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    int main()
    {
        long long  m,h1,a1,x1,y1,h2,a2,x2,y2;
        long long  p1,p2,q1,q2;
        while(cin >> m >> h1 >> a1 >> x1 >> y1 >> h2 >> a2 >> x2 >> y2){
            p1 = p2 = q1 = q2 = 0;
            for(long long  i = 1; i <= 2*m; i++){
                h1 = (h1*x1+y1)%m;
                if(h1 == a1){
                    if(p1 == 0)
                        p1 = i;
                    else if(q1 == 0){
                        q1 = i - p1;
                        break;
                    }
                }
            }
            for(long long i = 1; i <= 2*m; i++){
               h2 = (h2*x2+y2)%m;
               if(h2 == a2){
                   if(p2 == 0)
                       p2 = i;
                   else if(q2 == 0){
                       q2 = i - p2;
                       break;
                   }
               }
            }
            if(p1 == 0 || p2 == 0){
                puts("-1");
                continue;
            }
            long long ans1 = p1,ans2 = p2;
            long long i;
            for( i = 1; i <= 2 *m ;i++){
                if(ans1 == ans2){
                    printf("%lld
    ",ans1);
                    break;
                }
                if(ans1 > ans2){
                    ans2 += q2;
                }
                if(ans1 < ans2){
                    ans1 += q1;
                }
            }
            if( i > 2*m){
                puts("-1");
            }
        }
        return 0;
    }
        
    

      

    法二:拓展欧几里得

    用于处理计算ax+by = c 的x,y的值

    由已知数据我们容易可以的出p1,q1,p2,q2,依次是h1到a1的开始的时间,循环的时间,h2到a2的开始的时间,循环的时间,那么可以得到p1x+q1 = p2x+q2

    变形可得 p1x-p2x=q2-q1

    欧几里得 ax+b = c   gcd(a,b) = gcd(b,a%b)  当b=0时就是最大公约数,递归最大公约数的求法

    int gcd(int a,int b){
    return b == 0? a:gcd(b,a%b);

    }

    拓展欧几里得公式 ax+by=c

    int   exgcd(int  a,int  b){
        if(b == 0){
            x = 1;
            y = 0;
            return a;
        }
        int  d = exgcd(b,a%b);
        int  t = x;
        x = y;
        y = t - a/b*y;
        return d;
    }
    

     可以得到其中一个x,y的解(对于ax+by = gcd(a,b) 这个方程)

    定理:对于ax+by = gcd(a,b)来说肯定会存在x,y(为正整数)的解 

    所以最终的解为 x *= c/d,y *=c/d;如果c%d!=0说明无正整数解

    那么对于所有的x,y解集满足条件

    x = x + q2/d;

    y = y - q1/d;

    对于本题来说只要找到一个最小的x满足x,y都大于等于零,res = q1x+p1

    以上都是些结论

    详细证明 请看 http://www.cnblogs.com/ka200812/archive/2011/09/02/2164404.html  大神写的非常好orz

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    long long x,y;
    long long  exgcd(long long  a,long long  b){
        if(b == 0){
            x = 1;
            y = 0;
            return a;
        }
        long long  d = exgcd(b,a%b);
        long long  t = x;
        x = y;
        y = t - a/b*y;
        return d;
    }
    int main()
    {
        long long  m,h1,a1,x1,y1,h2,a2,x2,y2;
        long long  p1,p2,q1,q2;
        while(cin >> m >> h1 >> a1 >> x1 >> y1 >> h2 >> a2 >> x2 >> y2){
            p1 = p2 = q1 = q2 = 0;
            for(long long  i = 1; i <= 2*m; i++){
                h1 = (h1*x1+y1)%m;
                if(h1 == a1){
                    if(p1 == 0)
                        p1 = i;
                    else if(q1 == 0){
                        q1 = i - p1;
                        break;
                    }
                }
            }
            for(long long i = 1; i <= 2*m; i++){
               h2 = (h2*x2+y2)%m;
               if(h2 == a2){
                   if(p2 == 0)
                       p2 = i;
                   else if(q2 == 0){
                       q2 = i - p2;
                       break;
                   }
               }
            }
           long long d = exgcd(q1,-q2);
           long long c = p2 - p1;
           if(d == 0){
               puts("-1");
               continue;
           }
           if(c%d){
               puts("-1");
               continue;
           }
           if(d < 0 ) d = -d;
           if(p1 == 0 || p2 == 0){
               puts("-1");
               continue;
           }
           if(q2 == 0 && q1 == 0 && p1 != p2){
               puts("-1");
               continue;
           }
         //  printf("%I64d %I64d %I64d %I64d
    ",p1,p2,q1,q2);
           if((q2 == 0&&p2-p1 < 0) || (q1 == 0 && p1-p2< 0)){
               puts("-1");
               continue;
           }
         long long   k = c/d;
         if(exgcd(q1,-q2) < 0)
             x = -x,y = -y;
           x*= k; y*= k;
           if(x < 0 || y < 0)
           for( ; ;){
               x += q2/d;
               y += q1/d;
               if(x >= 0 && y >= 0)
                   break;
           }
           if(x > 0 && y > 0){
               for(; ;){
                   x -= q2/d;
                   y -= q1/d;
                   if( x < 0 || y < 0)
                       break;
               }
               x += q2/d;
               y += q1/d;
           }
    
           long long ans = x*q1+p1;
           printf("%I64d
    ",ans);
        }
        return 0;
    }
    

      

  • 相关阅读:
    c++ 有序二叉树的应用
    c++ 二叉树的遍历
    c++ 创建二叉树
    c++ 双向链表 的查找和删除
    c++ 双向循环链表
    c++ 双向链表
    Jzoj4209 已经没有什么好害怕的了
    Jzoj4209 已经没有什么好害怕的了
    后缀自动机转后缀树模板
    后缀自动机转后缀树模板
  • 原文地址:https://www.cnblogs.com/zero-begin/p/4533734.html
Copyright © 2011-2022 走看看