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 ;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值