zoukankan      html  css  js  c++  java
  • Floyed判环/龟兔算法

    [(5+2√6)2^x+1 ] mod p 的值,其中 0 ≤ x < 232 , p 是个质数,p ≤ 46337 .(这里介绍的是一种暴力的做法)

    (5+2√6)2^n+1 = an + bn·√6 ----©,

    (5-2√6)2^n+1 = an - bn·√6 ;

    所以(5+2√6)2^n+1 + (5-2√6)2^n+1 = 2an ;

    因为5-2√6<1 , 所以[(5+2√6)2^x+1= 2an - 1 ;

    然后(5+2√6)2^x+1 = (5+2√6) ·(an-1 + bn-1·√6) -----®;

    由C,R得:

    an=5an-1 + 12bn-1 ,

    bn=2an-1 + 5bn-1 ;

    所以我们要求的就是 a2^x+1 ;

    但是即使用矩阵快速幂复杂度为O(x) , 所以并卵 ; 同时矩阵并不能用 欧拉定理 进行优化。

    所以 波老师 就大胆的猜测对于这个问题 an mod p 的 循环节不会很大 , 所以之后就是暴力找循环节了。

    • floyed判圈算法描述:

    我们令周期为λ,非周期的长度大小为μ,

    他能在O(λ+μ)的时间复杂度 ,O(1)的空间复杂度内,得到λμ

    • 试用范围:

     functional graph:每个点只有一个出度的有向图。

    形象的一点说明如果 an = f (an-1) ,那么你就可以对这个数列用floyed判圈。

    (对于这道题就是 an = F (an-1 , bn-1) , bn = G (an-1 , bn-1) , 所以自然适用。)

    再比如 链表 ……

    • 描述及证明:

     我们设od为数列的初始状态,Next()为让an-1推出an的递推函数,和两个变量 turt , hare ,相遇点为 x , 进环点为 o

    首先我们令 turt = hare = od ;

    然后我们令turt , hare开始移动 : turt 没回合移动一个点 , 表示为 turt = Next (turt) ; hare 每回合移动两个点,表示为 hare = Next ( Next (hare)) ;

    如果画成图的话,你可以形象的认为,turt每回合只走一步,hare没回和走两步。

    然后我们可以得到两个结论:

    1. 如果Next () graph 没有环,那么在任何时刻 turt != hare ,并且两者是充要的。
    2. 如果Next () graph 有环 , 那么必然会有 turt == hare 的时候 , 让我来证明一下:

            

      hare跑啊跑啊,进到圈里了,但是他永远跑不出去了;turt跑啊~跑啊~ ,终于进圈了,它往逆时针的方向瞟了一眼,发现hare在他后面 y 个节点上,turt 心算了一下 再过 y / (2 - 1)的时间hare才追上自己,turt就开心的笑了。

      我们对 x 时的状态分析一下:

      turt : i = μ + a·λ + x ;

      hare : 2·i = μ + b·λ + x ;

      所以turt 到这一点所走的路程 i = (b - a)·λ -----À

      

      让我们继续分析下去,在 x 处turt , hare相遇了,我们可以认为在这时他们的路程差为 λ ,所以下一次相遇的时间为 λ / (2-1) = λ , 所以我们又可以得到两个结论:

          1.如果我们模拟turthare的下一次相遇,那么 turt 所走的路程 1·λ = λ , 所以周期求得。

          2.由1可知,两者相遇点仍旧是 x

      

      最后只剩下 μ 了:

          由À可知如果turt再往前走 μ 步,turt必然会回到 o 点 ,证明:i + μ Ξ μ (mod p) , 又因为从 od 走到 o 点需要 μ 步, 所以得证。

          那么又要怎么实现呢?我们令 turt 保持在 x 时的状态 , 让hare = od

          接下来让 turt , hare 以每回合都以 turt = Next(turt) , hare = Next (hare) 运动,那么他们又会相遇了,这一次显然是在o点相遇,记录这个走的步数及得到 μ 。

      伪代码:

      

    void Floyed () {
            pii hare = od , turt = od; 
            lam = mu = 0 ;
            int cnt = 0 ;
            while(1) {
                    hare = Next (Next (hare) ) ;
                    turt = Next ( turt) ;
                    if (hare.F == turt.F && hare.S == turt.S)  break ;
            } 
            while (1) {
                    hare = Next (Next (hare) ) ;
                    turt = Next (turt) ;
                    lam ++ ;
                    if (hare.F == turt.F && hare.S == turt.S)  break ;
            }
            hare = od ;
            while (1) {
                    hare = Next (hare) ;
                    turt = Next (turt) ;
                    if (hare.F == turt.F && hare.S == turt.S)  break ;
                    mu ++ ;
            }
            printf ("mu = %d , lam = %d
    " , mu , lam) ;
    }
    

     题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5451

    关于这道题目的后记:

    正解其实利用了 广义fib找循环节 的一个性质:http://blog.csdn.net/ACdreamers/article/details/25616461

    然后直接对(5+2√6)2^n+1 + (5-2√6)2^n+1用了二阶常系数线性递推,然后用伟达定理得到了an = 10·an-1 - an-2 ;       

    但是这种东西我不会,后来就想能不能用

    an=q·an-1 + p·bn-1 ,

    bn=s·an-1 + t·bn-1 ;

    推出an , an-1 , an-2 的关系式呢?

    然后真的找到了:an = (q+t) · an-1 + (p·s - q·t) · an-2 ;

    证明:

      p · bn - t · an = (ps - qt) · an-1 ;

      p · bn = (ps - qt) · an-1 + t · an ;

    所以:p · bn-1 = (ps - qt) · an-2 + t · an-1

    带回 an=q·an-1 + p·bn-1

    得证 an = (q+t) · an-1 + (p·s - q·t) · an-2 ;

  • 相关阅读:
    阿里p3c(代码规范,eclipse插件、模版,idea插件)
    mac 电脑 打开隐藏文件
    groovy安装 ideal
    JNI字段描述符
    java 中函数的参数传递详细介绍
    java把函数作为参数传递
    Android获取wifi MAC,关闭的wifi不能获取
    Android权限操作之uses-permission详解
    Android Studio断点调试
    android 启动socket 失败:socket(af_inet sock_stream 0) 返回-1
  • 原文地址:https://www.cnblogs.com/get-an-AC-everyday/p/4842632.html
Copyright © 2011-2022 走看看