D. Frog Jumping(裴蜀定理bfs)

Posted Lnn.

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了D. Frog Jumping(裴蜀定理bfs)相关的知识,希望对你有一定的参考价值。

前言:有趣的数论题 (因为表达式少写括号多d了一个小时的bug(晕


题目传送门


  题目类型:数论、裴蜀定理、bfs
  解析:先说一个结论,当n小于a+b时直接bfs;>=a+b时所有点x == k*gcd(a,b)都能到达
  bfs部分不说了,很基础。
  设青蛙向右跳跃x次,向左y次,到达了n,对于青蛙的跳跃轨迹,可以用一个方程表达:ax + by = n
  这个式子就很难不想到裴蜀定理:a、b是整数,那么一定存在整数x、y使得ax+by=gcd(a,b)。
  所以青蛙能够到达的点一定是g = gcd(a,b)的倍数
  写题的时候随便画了一下,发现n >= a+b时所有g的倍数都能够到达,感性证明一下:
  g = gcd(a,b) 。
  由裴蜀定理,一定存在ax - by == gcd(a,b),并且x>0。由于题目要求当前位置要一直大于等于0,对于x,y我们可以这样分配:当位置>=b时,尽量回撤,当<b时,只能向前走。此时最远会走到 b-1 + a。所以只要给出a+b的空间,就一定能走到gcd(a,b)的地方,重复这个过程k次,就能走到k*gcd(a,b)的地方。

  code:

void bfs(ll x , ll r)
    vis[x] = 1;
    ++now;
    if(x + a <= r && !vis[x+a])bfs(x+a,r);
    if(x - b >= 0 && !vis[x-b])bfs(x-b,r);

 
void solve()
    ll ans = 0;
    now = 0;
    g = gcd(a,b);
    ll aim = a+b-1;
    for(ll i = 0 ; i <= aim ; ++i)
        if( i == 0 || (i >= a && vis[i-a]) )
            bfs(i,i);
        
        ans += now;
        if(i == n)
            cout << ans << endl ;
            return;
        
    
    ll l = aim+1 , r = n;
    ans += (r-l+1);   ///补上0点的
    if(l/g == r/g)
        ans += (r-l+1) * (l/g);
    else if(l/g + 1 == r/g)
        ans += (r - r/g*g + 1) * (r/g);
        ans += ((l/g+1)*g - l) * (l/g);
    else 
        ans += (r - r/g*g + 1) * (r/g);
        ans += ((l/g+1)*g - l) * (l/g);
 
        l = l/g*g + g;
        r = r/g*g - 1;
        ans += (l/g*g + r/g*g) * (r/g - l/g + 1)/2;
    
    cout << ans << endl ;


以上是关于D. Frog Jumping(裴蜀定理bfs)的主要内容,如果未能解决你的问题,请参考以下文章

D. Frog Jumping(裴蜀定理bfs)

D. Not Quite Lee(裴蜀定理gcdlowbit)

D. Not Quite Lee(裴蜀定理gcdlowbit)

D. Not Quite Lee(裴蜀定理gcdlowbit)

Codeforces 290 BFox And Jumping

裴蜀定理 浅讲